blob: 8aaa325486f2e4a1772c6e8d194fad2e4500dec1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/include/server/AudioFlinger/AudioMixer.cpp
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "AudioMixer"
The Android Open Source Project10592532009-03-18 17:39:46 -070019//#define LOG_NDEBUG 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020
21#include <stdint.h>
22#include <string.h>
23#include <stdlib.h>
24#include <sys/types.h>
25
26#include <utils/Errors.h>
27#include <utils/Log.h>
28
29#include "AudioMixer.h"
30
31namespace android {
32// ----------------------------------------------------------------------------
33
34static inline int16_t clamp16(int32_t sample)
35{
36 if ((sample>>15) ^ (sample>>31))
37 sample = 0x7FFF ^ (sample>>31);
38 return sample;
39}
40
41// ----------------------------------------------------------------------------
42
43AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
44 : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)
45{
46 mState.enabledTracks= 0;
47 mState.needsChanged = 0;
48 mState.frameCount = frameCount;
49 mState.outputTemp = 0;
50 mState.resampleTemp = 0;
51 mState.hook = process__nop;
52 track_t* t = mState.tracks;
53 for (int i=0 ; i<32 ; i++) {
54 t->needs = 0;
55 t->volume[0] = UNITY_GAIN;
56 t->volume[1] = UNITY_GAIN;
57 t->volumeInc[0] = 0;
58 t->volumeInc[1] = 0;
Eric Laurent65b65452010-06-01 23:49:17 -070059 t->auxLevel = 0;
60 t->auxInc = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 t->channelCount = 2;
62 t->enabled = 0;
63 t->format = 16;
64 t->buffer.raw = 0;
65 t->bufferProvider = 0;
66 t->hook = 0;
67 t->resampler = 0;
68 t->sampleRate = mSampleRate;
69 t->in = 0;
Eric Laurent65b65452010-06-01 23:49:17 -070070 t->mainBuffer = NULL;
71 t->auxBuffer = NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 t++;
73 }
74}
75
76 AudioMixer::~AudioMixer()
77 {
78 track_t* t = mState.tracks;
79 for (int i=0 ; i<32 ; i++) {
80 delete t->resampler;
81 t++;
82 }
83 delete [] mState.outputTemp;
84 delete [] mState.resampleTemp;
85 }
86
87 int AudioMixer::getTrackName()
88 {
89 uint32_t names = mTrackNames;
90 uint32_t mask = 1;
91 int n = 0;
92 while (names & mask) {
93 mask <<= 1;
94 n++;
95 }
96 if (mask) {
97 LOGV("add track (%d)", n);
98 mTrackNames |= mask;
99 return TRACK0 + n;
100 }
101 return -1;
102 }
103
104 void AudioMixer::invalidateState(uint32_t mask)
105 {
106 if (mask) {
107 mState.needsChanged |= mask;
108 mState.hook = process__validate;
109 }
110 }
111
112 void AudioMixer::deleteTrackName(int name)
113 {
114 name -= TRACK0;
115 if (uint32_t(name) < MAX_NUM_TRACKS) {
116 LOGV("deleteTrackName(%d)", name);
117 track_t& track(mState.tracks[ name ]);
118 if (track.enabled != 0) {
119 track.enabled = 0;
120 invalidateState(1<<name);
121 }
122 if (track.resampler) {
123 // delete the resampler
124 delete track.resampler;
125 track.resampler = 0;
126 track.sampleRate = mSampleRate;
127 invalidateState(1<<name);
128 }
129 track.volumeInc[0] = 0;
130 track.volumeInc[1] = 0;
131 mTrackNames &= ~(1<<name);
132 }
133 }
134
135status_t AudioMixer::enable(int name)
136{
137 switch (name) {
138 case MIXING: {
139 if (mState.tracks[ mActiveTrack ].enabled != 1) {
140 mState.tracks[ mActiveTrack ].enabled = 1;
141 LOGV("enable(%d)", mActiveTrack);
142 invalidateState(1<<mActiveTrack);
143 }
144 } break;
145 default:
146 return NAME_NOT_FOUND;
147 }
148 return NO_ERROR;
149}
150
151status_t AudioMixer::disable(int name)
152{
153 switch (name) {
154 case MIXING: {
155 if (mState.tracks[ mActiveTrack ].enabled != 0) {
156 mState.tracks[ mActiveTrack ].enabled = 0;
157 LOGV("disable(%d)", mActiveTrack);
158 invalidateState(1<<mActiveTrack);
159 }
160 } break;
161 default:
162 return NAME_NOT_FOUND;
163 }
164 return NO_ERROR;
165}
166
167status_t AudioMixer::setActiveTrack(int track)
168{
169 if (uint32_t(track-TRACK0) >= MAX_NUM_TRACKS) {
170 return BAD_VALUE;
171 }
172 mActiveTrack = track - TRACK0;
173 return NO_ERROR;
174}
175
Eric Laurent65b65452010-06-01 23:49:17 -0700176status_t AudioMixer::setParameter(int target, int name, void *value)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177{
Eric Laurent65b65452010-06-01 23:49:17 -0700178 int valueInt = (int)value;
179 int32_t *valueBuf = (int32_t *)value;
180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 switch (target) {
182 case TRACK:
183 if (name == CHANNEL_COUNT) {
Eric Laurent65b65452010-06-01 23:49:17 -0700184 if ((uint32_t(valueInt) <= MAX_NUM_CHANNELS) && (valueInt)) {
185 if (mState.tracks[ mActiveTrack ].channelCount != valueInt) {
186 mState.tracks[ mActiveTrack ].channelCount = valueInt;
187 LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", valueInt);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 invalidateState(1<<mActiveTrack);
189 }
190 return NO_ERROR;
191 }
192 }
Eric Laurent65b65452010-06-01 23:49:17 -0700193 if (name == MAIN_BUFFER) {
194 if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) {
195 mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
196 LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
197 invalidateState(1<<mActiveTrack);
198 }
199 return NO_ERROR;
200 }
201 if (name == AUX_BUFFER) {
202 if (mState.tracks[ mActiveTrack ].auxBuffer != valueBuf) {
203 mState.tracks[ mActiveTrack ].auxBuffer = valueBuf;
204 LOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf);
205 invalidateState(1<<mActiveTrack);
206 }
207 return NO_ERROR;
208 }
209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 break;
211 case RESAMPLE:
212 if (name == SAMPLE_RATE) {
Eric Laurent65b65452010-06-01 23:49:17 -0700213 if (valueInt > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 track_t& track = mState.tracks[ mActiveTrack ];
Eric Laurent65b65452010-06-01 23:49:17 -0700215 if (track.setResampler(uint32_t(valueInt), mSampleRate)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
Eric Laurent65b65452010-06-01 23:49:17 -0700217 uint32_t(valueInt));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 invalidateState(1<<mActiveTrack);
219 }
220 return NO_ERROR;
221 }
222 }
223 break;
224 case RAMP_VOLUME:
225 case VOLUME:
226 if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
227 track_t& track = mState.tracks[ mActiveTrack ];
Eric Laurent65b65452010-06-01 23:49:17 -0700228 if (track.volume[name-VOLUME0] != valueInt) {
229 LOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
Eric Laurent65b65452010-06-01 23:49:17 -0700231 track.volume[name-VOLUME0] = valueInt;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 if (target == VOLUME) {
Eric Laurent65b65452010-06-01 23:49:17 -0700233 track.prevVolume[name-VOLUME0] = valueInt << 16;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 track.volumeInc[name-VOLUME0] = 0;
235 } else {
Eric Laurent65b65452010-06-01 23:49:17 -0700236 int32_t d = (valueInt<<16) - track.prevVolume[name-VOLUME0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 int32_t volInc = d / int32_t(mState.frameCount);
238 track.volumeInc[name-VOLUME0] = volInc;
239 if (volInc == 0) {
Eric Laurent65b65452010-06-01 23:49:17 -0700240 track.prevVolume[name-VOLUME0] = valueInt << 16;
241 }
242 }
243 invalidateState(1<<mActiveTrack);
244 }
245 return NO_ERROR;
246 } else if (name == AUXLEVEL) {
247 track_t& track = mState.tracks[ mActiveTrack ];
248 if (track.auxLevel != valueInt) {
249 LOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt);
250 track.prevAuxLevel = track.auxLevel << 16;
251 track.auxLevel = valueInt;
252 if (target == VOLUME) {
253 track.prevAuxLevel = valueInt << 16;
254 track.auxInc = 0;
255 } else {
256 int32_t d = (valueInt<<16) - track.prevAuxLevel;
257 int32_t volInc = d / int32_t(mState.frameCount);
258 track.auxInc = volInc;
259 if (volInc == 0) {
260 track.prevAuxLevel = valueInt << 16;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 }
262 }
263 invalidateState(1<<mActiveTrack);
264 }
265 return NO_ERROR;
266 }
267 break;
268 }
269 return BAD_VALUE;
270}
271
272bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
273{
274 if (value!=devSampleRate || resampler) {
275 if (sampleRate != value) {
276 sampleRate = value;
277 if (resampler == 0) {
278 resampler = AudioResampler::create(
279 format, channelCount, devSampleRate);
280 }
281 return true;
282 }
283 }
284 return false;
285}
286
287bool AudioMixer::track_t::doesResample() const
288{
289 return resampler != 0;
290}
291
292inline
Eric Laurent65b65452010-06-01 23:49:17 -0700293void AudioMixer::track_t::adjustVolumeRamp(bool aux)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294{
295 for (int i=0 ; i<2 ; i++) {
296 if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
297 ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
298 volumeInc[i] = 0;
299 prevVolume[i] = volume[i]<<16;
300 }
301 }
Eric Laurent65b65452010-06-01 23:49:17 -0700302 if (aux) {
303 if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) ||
304 ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) {
305 auxInc = 0;
306 prevAuxLevel = auxLevel<<16;
307 }
308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309}
310
311
312status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
313{
314 mState.tracks[ mActiveTrack ].bufferProvider = buffer;
315 return NO_ERROR;
316}
317
318
319
Eric Laurent65b65452010-06-01 23:49:17 -0700320void AudioMixer::process()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321{
Eric Laurent65b65452010-06-01 23:49:17 -0700322 mState.hook(&mState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323}
324
325
Eric Laurent65b65452010-06-01 23:49:17 -0700326void AudioMixer::process__validate(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327{
328 LOGW_IF(!state->needsChanged,
329 "in process__validate() but nothing's invalid");
330
331 uint32_t changed = state->needsChanged;
332 state->needsChanged = 0; // clear the validation flag
333
334 // recompute which tracks are enabled / disabled
335 uint32_t enabled = 0;
336 uint32_t disabled = 0;
337 while (changed) {
338 const int i = 31 - __builtin_clz(changed);
339 const uint32_t mask = 1<<i;
340 changed &= ~mask;
341 track_t& t = state->tracks[i];
342 (t.enabled ? enabled : disabled) |= mask;
343 }
344 state->enabledTracks &= ~disabled;
345 state->enabledTracks |= enabled;
346
347 // compute everything we need...
348 int countActiveTracks = 0;
349 int all16BitsStereoNoResample = 1;
350 int resampling = 0;
351 int volumeRamp = 0;
352 uint32_t en = state->enabledTracks;
353 while (en) {
354 const int i = 31 - __builtin_clz(en);
355 en &= ~(1<<i);
356
357 countActiveTracks++;
358 track_t& t = state->tracks[i];
359 uint32_t n = 0;
360 n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
361 n |= NEEDS_FORMAT_16;
362 n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
Eric Laurent65b65452010-06-01 23:49:17 -0700363 if (t.auxLevel != 0 && t.auxBuffer != NULL) {
364 n |= NEEDS_AUX_ENABLED;
365 }
366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 if (t.volumeInc[0]|t.volumeInc[1]) {
368 volumeRamp = 1;
369 } else if (!t.doesResample() && t.volumeRL == 0) {
370 n |= NEEDS_MUTE_ENABLED;
371 }
372 t.needs = n;
373
374 if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
375 t.hook = track__nop;
376 } else {
Eric Laurent65b65452010-06-01 23:49:17 -0700377 if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
378 all16BitsStereoNoResample = 0;
379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
381 all16BitsStereoNoResample = 0;
382 resampling = 1;
383 t.hook = track__genericResample;
384 } else {
385 if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
386 t.hook = track__16BitsMono;
387 all16BitsStereoNoResample = 0;
388 }
389 if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){
390 t.hook = track__16BitsStereo;
391 }
392 }
393 }
394 }
395
396 // select the processing hooks
397 state->hook = process__nop;
398 if (countActiveTracks) {
399 if (resampling) {
400 if (!state->outputTemp) {
401 state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
402 }
403 if (!state->resampleTemp) {
404 state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
405 }
406 state->hook = process__genericResampling;
407 } else {
408 if (state->outputTemp) {
409 delete [] state->outputTemp;
410 state->outputTemp = 0;
411 }
412 if (state->resampleTemp) {
413 delete [] state->resampleTemp;
414 state->resampleTemp = 0;
415 }
416 state->hook = process__genericNoResampling;
417 if (all16BitsStereoNoResample && !volumeRamp) {
418 if (countActiveTracks == 1) {
419 state->hook = process__OneTrack16BitsStereoNoResampling;
420 }
421 }
422 }
423 }
424
425 LOGV("mixer configuration change: %d activeTracks (%08x) "
426 "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d",
427 countActiveTracks, state->enabledTracks,
428 all16BitsStereoNoResample, resampling, volumeRamp);
429
Eric Laurent65b65452010-06-01 23:49:17 -0700430 state->hook(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431
432 // Now that the volume ramp has been done, set optimal state and
433 // track hooks for subsequent mixer process
434 if (countActiveTracks) {
435 int allMuted = 1;
436 uint32_t en = state->enabledTracks;
437 while (en) {
438 const int i = 31 - __builtin_clz(en);
439 en &= ~(1<<i);
440 track_t& t = state->tracks[i];
441 if (!t.doesResample() && t.volumeRL == 0)
442 {
443 t.needs |= NEEDS_MUTE_ENABLED;
444 t.hook = track__nop;
445 } else {
446 allMuted = 0;
447 }
448 }
449 if (allMuted) {
450 state->hook = process__nop;
Eric Laurent65b65452010-06-01 23:49:17 -0700451 } else if (all16BitsStereoNoResample) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 if (countActiveTracks == 1) {
453 state->hook = process__OneTrack16BitsStereoNoResampling;
454 }
455 }
456 }
457}
458
459static inline
460int32_t mulAdd(int16_t in, int16_t v, int32_t a)
461{
462#if defined(__arm__) && !defined(__thumb__)
463 int32_t out;
464 asm( "smlabb %[out], %[in], %[v], %[a] \n"
465 : [out]"=r"(out)
466 : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
467 : );
468 return out;
469#else
470 return a + in * int32_t(v);
471#endif
472}
473
474static inline
475int32_t mul(int16_t in, int16_t v)
476{
477#if defined(__arm__) && !defined(__thumb__)
478 int32_t out;
479 asm( "smulbb %[out], %[in], %[v] \n"
480 : [out]"=r"(out)
481 : [in]"%r"(in), [v]"r"(v)
482 : );
483 return out;
484#else
485 return in * int32_t(v);
486#endif
487}
488
489static inline
490int32_t mulAddRL(int left, uint32_t inRL, uint32_t vRL, int32_t a)
491{
492#if defined(__arm__) && !defined(__thumb__)
493 int32_t out;
494 if (left) {
495 asm( "smlabb %[out], %[inRL], %[vRL], %[a] \n"
496 : [out]"=r"(out)
497 : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
498 : );
499 } else {
500 asm( "smlatt %[out], %[inRL], %[vRL], %[a] \n"
501 : [out]"=r"(out)
502 : [inRL]"%r"(inRL), [vRL]"r"(vRL), [a]"r"(a)
503 : );
504 }
505 return out;
506#else
507 if (left) {
508 return a + int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
509 } else {
510 return a + int16_t(inRL>>16) * int16_t(vRL>>16);
511 }
512#endif
513}
514
515static inline
516int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
517{
518#if defined(__arm__) && !defined(__thumb__)
519 int32_t out;
520 if (left) {
521 asm( "smulbb %[out], %[inRL], %[vRL] \n"
522 : [out]"=r"(out)
523 : [inRL]"%r"(inRL), [vRL]"r"(vRL)
524 : );
525 } else {
526 asm( "smultt %[out], %[inRL], %[vRL] \n"
527 : [out]"=r"(out)
528 : [inRL]"%r"(inRL), [vRL]"r"(vRL)
529 : );
530 }
531 return out;
532#else
533 if (left) {
534 return int16_t(inRL&0xFFFF) * int16_t(vRL&0xFFFF);
535 } else {
536 return int16_t(inRL>>16) * int16_t(vRL>>16);
537 }
538#endif
539}
540
541
Eric Laurent65b65452010-06-01 23:49:17 -0700542void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543{
544 t->resampler->setSampleRate(t->sampleRate);
545
546 // ramp gain - resample to temp buffer and scale/mix in 2nd step
Eric Laurent65b65452010-06-01 23:49:17 -0700547 if (aux != NULL) {
548 // always resample with unity gain when sending to auxiliary buffer to be able
549 // to apply send level after resampling
550 // TODO: modify each resampler to support aux channel?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
552 memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
553 t->resampler->resample(temp, outFrameCount, t->bufferProvider);
Eric Laurent65b65452010-06-01 23:49:17 -0700554 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
555 volumeRampStereo(t, out, outFrameCount, temp, aux);
556 } else {
557 volumeStereo(t, out, outFrameCount, temp, aux);
558 }
559 } else {
560 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
561 t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
562 memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
563 t->resampler->resample(temp, outFrameCount, t->bufferProvider);
564 volumeRampStereo(t, out, outFrameCount, temp, aux);
565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566
Eric Laurent65b65452010-06-01 23:49:17 -0700567 // constant gain
568 else {
569 t->resampler->setVolume(t->volume[0], t->volume[1]);
570 t->resampler->resample(out, outFrameCount, t->bufferProvider);
571 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 }
573}
574
Eric Laurent65b65452010-06-01 23:49:17 -0700575void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576{
577}
578
Eric Laurent65b65452010-06-01 23:49:17 -0700579void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580{
581 int32_t vl = t->prevVolume[0];
582 int32_t vr = t->prevVolume[1];
583 const int32_t vlInc = t->volumeInc[0];
584 const int32_t vrInc = t->volumeInc[1];
585
586 //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
587 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
588 // (vl + vlInc*frameCount)/65536.0f, frameCount);
Eric Laurent65b65452010-06-01 23:49:17 -0700589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 // ramp volume
Eric Laurent65b65452010-06-01 23:49:17 -0700591 if UNLIKELY(aux != NULL) {
592 int32_t va = t->prevAuxLevel;
593 const int32_t vaInc = t->auxInc;
594 int32_t l;
595 int32_t r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596
597 do {
Eric Laurent65b65452010-06-01 23:49:17 -0700598 l = (*temp++ >> 12);
599 r = (*temp++ >> 12);
600 *out++ += (vl >> 16) * l;
601 *out++ += (vr >> 16) * r;
602 *aux++ += (va >> 17) * (l + r);
603 vl += vlInc;
604 vr += vrInc;
605 va += vaInc;
606 } while (--frameCount);
607 t->prevAuxLevel = va;
608 } else {
609 do {
610 *out++ += (vl >> 16) * (*temp++ >> 12);
611 *out++ += (vr >> 16) * (*temp++ >> 12);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 vl += vlInc;
613 vr += vrInc;
614 } while (--frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 }
Eric Laurent65b65452010-06-01 23:49:17 -0700616 t->prevVolume[0] = vl;
617 t->prevVolume[1] = vr;
618 t->adjustVolumeRamp((aux != NULL));
619}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620
Eric Laurent65b65452010-06-01 23:49:17 -0700621void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
622{
623 const int16_t vl = t->volume[0];
624 const int16_t vr = t->volume[1];
625
626 if UNLIKELY(aux != NULL) {
627 const int16_t va = (int16_t)t->auxLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 do {
Eric Laurent65b65452010-06-01 23:49:17 -0700629 int16_t l = (int16_t)(*temp++ >> 12);
630 int16_t r = (int16_t)(*temp++ >> 12);
631 out[0] = mulAdd(l, vl, out[0]);
632 int16_t a = (int16_t)(((int32_t)l + r) >> 1);
633 out[1] = mulAdd(r, vr, out[1]);
634 out += 2;
635 aux[0] = mulAdd(a, va, aux[0]);
636 aux++;
637 } while (--frameCount);
638 } else {
639 do {
640 int16_t l = (int16_t)(*temp++ >> 12);
641 int16_t r = (int16_t)(*temp++ >> 12);
642 out[0] = mulAdd(l, vl, out[0]);
643 out[1] = mulAdd(r, vr, out[1]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 out += 2;
645 } while (--frameCount);
646 }
Eric Laurent65b65452010-06-01 23:49:17 -0700647}
648
649void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
650{
651 int16_t const *in = static_cast<int16_t const *>(t->in);
652
653 if UNLIKELY(aux != NULL) {
654 int32_t l;
655 int32_t r;
656 // ramp gain
657 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
658 int32_t vl = t->prevVolume[0];
659 int32_t vr = t->prevVolume[1];
660 int32_t va = t->prevAuxLevel;
661 const int32_t vlInc = t->volumeInc[0];
662 const int32_t vrInc = t->volumeInc[1];
663 const int32_t vaInc = t->auxInc;
664 // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
665 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
666 // (vl + vlInc*frameCount)/65536.0f, frameCount);
667
668 do {
669 l = (int32_t)*in++;
670 r = (int32_t)*in++;
671 *out++ += (vl >> 16) * l;
672 *out++ += (vr >> 16) * r;
673 *aux++ += (va >> 17) * (l + r);
674 vl += vlInc;
675 vr += vrInc;
676 va += vaInc;
677 } while (--frameCount);
678
679 t->prevVolume[0] = vl;
680 t->prevVolume[1] = vr;
681 t->prevAuxLevel = va;
682 t->adjustVolumeRamp(true);
683 }
684
685 // constant gain
686 else {
687 const uint32_t vrl = t->volumeRL;
688 const int16_t va = (int16_t)t->auxLevel;
689 do {
690 uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
691 int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1);
692 in += 2;
693 out[0] = mulAddRL(1, rl, vrl, out[0]);
694 out[1] = mulAddRL(0, rl, vrl, out[1]);
695 out += 2;
696 aux[0] = mulAdd(a, va, aux[0]);
697 aux++;
698 } while (--frameCount);
699 }
700 } else {
701 // ramp gain
702 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
703 int32_t vl = t->prevVolume[0];
704 int32_t vr = t->prevVolume[1];
705 const int32_t vlInc = t->volumeInc[0];
706 const int32_t vrInc = t->volumeInc[1];
707
708 // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
709 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
710 // (vl + vlInc*frameCount)/65536.0f, frameCount);
711
712 do {
713 *out++ += (vl >> 16) * (int32_t) *in++;
714 *out++ += (vr >> 16) * (int32_t) *in++;
715 vl += vlInc;
716 vr += vrInc;
717 } while (--frameCount);
718
719 t->prevVolume[0] = vl;
720 t->prevVolume[1] = vr;
721 t->adjustVolumeRamp(false);
722 }
723
724 // constant gain
725 else {
726 const uint32_t vrl = t->volumeRL;
727 do {
728 uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
729 in += 2;
730 out[0] = mulAddRL(1, rl, vrl, out[0]);
731 out[1] = mulAddRL(0, rl, vrl, out[1]);
732 out += 2;
733 } while (--frameCount);
734 }
735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 t->in = in;
737}
738
Eric Laurent65b65452010-06-01 23:49:17 -0700739void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740{
741 int16_t const *in = static_cast<int16_t const *>(t->in);
742
Eric Laurent65b65452010-06-01 23:49:17 -0700743 if UNLIKELY(aux != NULL) {
744 // ramp gain
745 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
746 int32_t vl = t->prevVolume[0];
747 int32_t vr = t->prevVolume[1];
748 int32_t va = t->prevAuxLevel;
749 const int32_t vlInc = t->volumeInc[0];
750 const int32_t vrInc = t->volumeInc[1];
751 const int32_t vaInc = t->auxInc;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752
Eric Laurent65b65452010-06-01 23:49:17 -0700753 // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
754 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
755 // (vl + vlInc*frameCount)/65536.0f, frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756
Eric Laurent65b65452010-06-01 23:49:17 -0700757 do {
758 int32_t l = *in++;
759 *out++ += (vl >> 16) * l;
760 *out++ += (vr >> 16) * l;
761 *aux++ += (va >> 16) * l;
762 vl += vlInc;
763 vr += vrInc;
764 va += vaInc;
765 } while (--frameCount);
766
767 t->prevVolume[0] = vl;
768 t->prevVolume[1] = vr;
769 t->prevAuxLevel = va;
770 t->adjustVolumeRamp(true);
771 }
772 // constant gain
773 else {
774 const int16_t vl = t->volume[0];
775 const int16_t vr = t->volume[1];
776 const int16_t va = (int16_t)t->auxLevel;
777 do {
778 int16_t l = *in++;
779 out[0] = mulAdd(l, vl, out[0]);
780 out[1] = mulAdd(l, vr, out[1]);
781 out += 2;
782 aux[0] = mulAdd(l, va, aux[0]);
783 aux++;
784 } while (--frameCount);
785 }
786 } else {
787 // ramp gain
788 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
789 int32_t vl = t->prevVolume[0];
790 int32_t vr = t->prevVolume[1];
791 const int32_t vlInc = t->volumeInc[0];
792 const int32_t vrInc = t->volumeInc[1];
793
794 // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
795 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
796 // (vl + vlInc*frameCount)/65536.0f, frameCount);
797
798 do {
799 int32_t l = *in++;
800 *out++ += (vl >> 16) * l;
801 *out++ += (vr >> 16) * l;
802 vl += vlInc;
803 vr += vrInc;
804 } while (--frameCount);
805
806 t->prevVolume[0] = vl;
807 t->prevVolume[1] = vr;
808 t->adjustVolumeRamp(false);
809 }
810 // constant gain
811 else {
812 const int16_t vl = t->volume[0];
813 const int16_t vr = t->volume[1];
814 do {
815 int16_t l = *in++;
816 out[0] = mulAdd(l, vl, out[0]);
817 out[1] = mulAdd(l, vr, out[1]);
818 out += 2;
819 } while (--frameCount);
820 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 }
822 t->in = in;
823}
824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
826{
827 for (size_t i=0 ; i<c ; i++) {
828 int32_t l = *sums++;
829 int32_t r = *sums++;
830 int32_t nl = l >> 12;
831 int32_t nr = r >> 12;
832 l = clamp16(nl);
833 r = clamp16(nr);
834 *out++ = (r<<16) | (l & 0xFFFF);
835 }
836}
837
838// no-op case
Eric Laurent65b65452010-06-01 23:49:17 -0700839void AudioMixer::process__nop(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840{
Eric Laurent65b65452010-06-01 23:49:17 -0700841 uint32_t e0 = state->enabledTracks;
842 size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
843 while (e0) {
844 // process by group of tracks with same output buffer to
845 // avoid multiple memset() on same buffer
846 uint32_t e1 = e0, e2 = e0;
847 int i = 31 - __builtin_clz(e1);
848 track_t& t1 = state->tracks[i];
849 e2 &= ~(1<<i);
850 while (e2) {
851 i = 31 - __builtin_clz(e2);
852 e2 &= ~(1<<i);
853 track_t& t2 = state->tracks[i];
854 if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
855 e1 &= ~(1<<i);
856 }
857 }
858 e0 &= ~(e1);
859
860 memset(t1.mainBuffer, 0, bufSize);
861
862 while (e1) {
863 i = 31 - __builtin_clz(e1);
864 e1 &= ~(1<<i);
865 t1 = state->tracks[i];
866 size_t outFrames = state->frameCount;
867 while (outFrames) {
868 t1.buffer.frameCount = outFrames;
869 t1.bufferProvider->getNextBuffer(&t1.buffer);
870 if (!t1.buffer.raw) break;
871 outFrames -= t1.buffer.frameCount;
872 t1.bufferProvider->releaseBuffer(&t1.buffer);
873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 }
875 }
876}
877
878// generic code without resampling
Eric Laurent65b65452010-06-01 23:49:17 -0700879void AudioMixer::process__genericNoResampling(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880{
881 int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
882
883 // acquire each track's buffer
884 uint32_t enabledTracks = state->enabledTracks;
Eric Laurent65b65452010-06-01 23:49:17 -0700885 uint32_t e0 = enabledTracks;
886 while (e0) {
887 const int i = 31 - __builtin_clz(e0);
888 e0 &= ~(1<<i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 track_t& t = state->tracks[i];
890 t.buffer.frameCount = state->frameCount;
891 t.bufferProvider->getNextBuffer(&t.buffer);
892 t.frameCount = t.buffer.frameCount;
893 t.in = t.buffer.raw;
894 // t.in == NULL can happen if the track was flushed just after having
895 // been enabled for mixing.
896 if (t.in == NULL)
897 enabledTracks &= ~(1<<i);
898 }
899
Eric Laurent65b65452010-06-01 23:49:17 -0700900 e0 = enabledTracks;
901 while (e0) {
902 // process by group of tracks with same output buffer to
903 // optimize cache use
904 uint32_t e1 = e0, e2 = e0;
905 int j = 31 - __builtin_clz(e1);
906 track_t& t1 = state->tracks[j];
907 e2 &= ~(1<<j);
908 while (e2) {
909 j = 31 - __builtin_clz(e2);
910 e2 &= ~(1<<j);
911 track_t& t2 = state->tracks[j];
912 if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
913 e1 &= ~(1<<j);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 }
915 }
Eric Laurent65b65452010-06-01 23:49:17 -0700916 e0 &= ~(e1);
917 // this assumes output 16 bits stereo, no resampling
918 int32_t *out = t1.mainBuffer;
919 size_t numFrames = 0;
920 do {
921 memset(outTemp, 0, sizeof(outTemp));
922 e2 = e1;
923 while (e2) {
924 const int i = 31 - __builtin_clz(e2);
925 e2 &= ~(1<<i);
926 track_t& t = state->tracks[i];
927 size_t outFrames = BLOCKSIZE;
928 int32_t *aux = NULL;
929 if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
930 aux = t.auxBuffer + numFrames;
931 }
932 while (outFrames) {
933 size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
934 if (inFrames) {
935 (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
936 t.frameCount -= inFrames;
937 outFrames -= inFrames;
938 if UNLIKELY(aux != NULL) {
939 aux += inFrames;
940 }
941 }
942 if (t.frameCount == 0 && outFrames) {
943 t.bufferProvider->releaseBuffer(&t.buffer);
944 t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
945 t.bufferProvider->getNextBuffer(&t.buffer);
946 t.in = t.buffer.raw;
947 if (t.in == NULL) {
948 enabledTracks &= ~(1<<i);
949 e1 &= ~(1<<i);
950 break;
951 }
952 t.frameCount = t.buffer.frameCount;
953 }
954 }
955 }
956 ditherAndClamp(out, outTemp, BLOCKSIZE);
957 out += BLOCKSIZE;
958 numFrames += BLOCKSIZE;
959 } while (numFrames < state->frameCount);
960 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961
962 // release each track's buffer
Eric Laurent65b65452010-06-01 23:49:17 -0700963 e0 = enabledTracks;
964 while (e0) {
965 const int i = 31 - __builtin_clz(e0);
966 e0 &= ~(1<<i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 track_t& t = state->tracks[i];
968 t.bufferProvider->releaseBuffer(&t.buffer);
969 }
970}
971
Eric Laurent65b65452010-06-01 23:49:17 -0700972
973 // generic code with resampling
974void AudioMixer::process__genericResampling(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975{
976 int32_t* const outTemp = state->outputTemp;
977 const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
978 memset(outTemp, 0, size);
979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 size_t numFrames = state->frameCount;
981
Eric Laurent65b65452010-06-01 23:49:17 -0700982 uint32_t e0 = state->enabledTracks;
983 while (e0) {
984 // process by group of tracks with same output buffer
985 // to optimize cache use
986 uint32_t e1 = e0, e2 = e0;
987 int j = 31 - __builtin_clz(e1);
988 track_t& t1 = state->tracks[j];
989 e2 &= ~(1<<j);
990 while (e2) {
991 j = 31 - __builtin_clz(e2);
992 e2 &= ~(1<<j);
993 track_t& t2 = state->tracks[j];
994 if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
995 e1 &= ~(1<<j);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 }
997 }
Eric Laurent65b65452010-06-01 23:49:17 -0700998 e0 &= ~(e1);
999 int32_t *out = t1.mainBuffer;
1000 while (e1) {
1001 const int i = 31 - __builtin_clz(e1);
1002 e1 &= ~(1<<i);
1003 track_t& t = state->tracks[i];
1004 int32_t *aux = NULL;
1005 if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
1006 aux = t.auxBuffer;
1007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008
Eric Laurent65b65452010-06-01 23:49:17 -07001009 // this is a little goofy, on the resampling case we don't
1010 // acquire/release the buffers because it's done by
1011 // the resampler.
1012 if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
1013 (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
1014 } else {
1015
1016 size_t outFrames = 0;
1017
1018 while (outFrames < numFrames) {
1019 t.buffer.frameCount = numFrames - outFrames;
1020 t.bufferProvider->getNextBuffer(&t.buffer);
1021 t.in = t.buffer.raw;
1022 // t.in == NULL can happen if the track was flushed just after having
1023 // been enabled for mixing.
1024 if (t.in == NULL) break;
1025
1026 if UNLIKELY(aux != NULL) {
1027 aux += outFrames;
1028 }
1029 (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
1030 outFrames += t.buffer.frameCount;
1031 t.bufferProvider->releaseBuffer(&t.buffer);
1032 }
1033 }
1034 }
1035 ditherAndClamp(out, outTemp, numFrames);
1036 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037}
1038
1039// one track, 16 bits stereo without resampling is the most common case
Eric Laurent65b65452010-06-01 23:49:17 -07001040void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041{
1042 const int i = 31 - __builtin_clz(state->enabledTracks);
1043 const track_t& t = state->tracks[i];
1044
1045 AudioBufferProvider::Buffer& b(t.buffer);
Eric Laurent65b65452010-06-01 23:49:17 -07001046
1047 int32_t* out = t.mainBuffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 size_t numFrames = state->frameCount;
Eric Laurent65b65452010-06-01 23:49:17 -07001049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 const int16_t vl = t.volume[0];
1051 const int16_t vr = t.volume[1];
1052 const uint32_t vrl = t.volumeRL;
1053 while (numFrames) {
1054 b.frameCount = numFrames;
1055 t.bufferProvider->getNextBuffer(&b);
1056 int16_t const *in = b.i16;
1057
1058 // in == NULL can happen if the track was flushed just after having
1059 // been enabled for mixing.
The Android Open Source Project10592532009-03-18 17:39:46 -07001060 if (in == NULL || ((unsigned long)in & 3)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
The Android Open Source Project10592532009-03-18 17:39:46 -07001062 LOGE_IF(((unsigned long)in & 3), "process stereo track: input buffer alignment pb: buffer %p track %d, channels %d, needs %08x",
1063 in, i, t.channelCount, t.needs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 return;
1065 }
1066 size_t outFrames = b.frameCount;
Eric Laurent65b65452010-06-01 23:49:17 -07001067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
1069 // volume is boosted, so we might need to clamp even though
1070 // we process only one track.
1071 do {
1072 uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
1073 in += 2;
1074 int32_t l = mulRL(1, rl, vrl) >> 12;
1075 int32_t r = mulRL(0, rl, vrl) >> 12;
1076 // clamping...
1077 l = clamp16(l);
1078 r = clamp16(r);
1079 *out++ = (r<<16) | (l & 0xFFFF);
1080 } while (--outFrames);
1081 } else {
1082 do {
1083 uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
1084 in += 2;
1085 int32_t l = mulRL(1, rl, vrl) >> 12;
1086 int32_t r = mulRL(0, rl, vrl) >> 12;
1087 *out++ = (r<<16) | (l & 0xFFFF);
1088 } while (--outFrames);
1089 }
1090 numFrames -= b.frameCount;
1091 t.bufferProvider->releaseBuffer(&b);
1092 }
1093}
1094
1095// 2 tracks is also a common case
Eric Laurent65b65452010-06-01 23:49:17 -07001096// NEVER used in current implementation of process__validate()
1097// only use if the 2 tracks have the same output buffer
1098void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099{
1100 int i;
1101 uint32_t en = state->enabledTracks;
1102
1103 i = 31 - __builtin_clz(en);
1104 const track_t& t0 = state->tracks[i];
1105 AudioBufferProvider::Buffer& b0(t0.buffer);
1106
1107 en &= ~(1<<i);
1108 i = 31 - __builtin_clz(en);
1109 const track_t& t1 = state->tracks[i];
1110 AudioBufferProvider::Buffer& b1(t1.buffer);
Eric Laurent65b65452010-06-01 23:49:17 -07001111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 int16_t const *in0;
1113 const int16_t vl0 = t0.volume[0];
1114 const int16_t vr0 = t0.volume[1];
1115 size_t frameCount0 = 0;
Eric Laurent65b65452010-06-01 23:49:17 -07001116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 int16_t const *in1;
1118 const int16_t vl1 = t1.volume[0];
1119 const int16_t vr1 = t1.volume[1];
1120 size_t frameCount1 = 0;
Eric Laurent65b65452010-06-01 23:49:17 -07001121
1122 //FIXME: only works if two tracks use same buffer
1123 int32_t* out = t0.mainBuffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 size_t numFrames = state->frameCount;
1125 int16_t const *buff = NULL;
1126
Eric Laurent65b65452010-06-01 23:49:17 -07001127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 while (numFrames) {
Eric Laurent65b65452010-06-01 23:49:17 -07001129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 if (frameCount0 == 0) {
1131 b0.frameCount = numFrames;
1132 t0.bufferProvider->getNextBuffer(&b0);
1133 if (b0.i16 == NULL) {
1134 if (buff == NULL) {
1135 buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
1136 }
1137 in0 = buff;
1138 b0.frameCount = numFrames;
1139 } else {
1140 in0 = b0.i16;
1141 }
1142 frameCount0 = b0.frameCount;
1143 }
1144 if (frameCount1 == 0) {
1145 b1.frameCount = numFrames;
1146 t1.bufferProvider->getNextBuffer(&b1);
1147 if (b1.i16 == NULL) {
1148 if (buff == NULL) {
1149 buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
1150 }
1151 in1 = buff;
1152 b1.frameCount = numFrames;
1153 } else {
1154 in1 = b1.i16;
1155 }
1156 frameCount1 = b1.frameCount;
1157 }
Eric Laurent65b65452010-06-01 23:49:17 -07001158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
1160
1161 numFrames -= outFrames;
1162 frameCount0 -= outFrames;
1163 frameCount1 -= outFrames;
Eric Laurent65b65452010-06-01 23:49:17 -07001164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 do {
1166 int32_t l0 = *in0++;
1167 int32_t r0 = *in0++;
1168 l0 = mul(l0, vl0);
1169 r0 = mul(r0, vr0);
1170 int32_t l = *in1++;
1171 int32_t r = *in1++;
1172 l = mulAdd(l, vl1, l0) >> 12;
1173 r = mulAdd(r, vr1, r0) >> 12;
1174 // clamping...
1175 l = clamp16(l);
1176 r = clamp16(r);
1177 *out++ = (r<<16) | (l & 0xFFFF);
1178 } while (--outFrames);
Eric Laurent65b65452010-06-01 23:49:17 -07001179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 if (frameCount0 == 0) {
1181 t0.bufferProvider->releaseBuffer(&b0);
1182 }
1183 if (frameCount1 == 0) {
1184 t1.bufferProvider->releaseBuffer(&b1);
1185 }
Eric Laurent65b65452010-06-01 23:49:17 -07001186 }
1187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 if (buff != NULL) {
Eric Laurent65b65452010-06-01 23:49:17 -07001189 delete [] buff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190 }
1191}
1192
1193// ----------------------------------------------------------------------------
1194}; // namespace android
1195