blob: fe56771b482d8c4856b622a5a262b8f48997ed59 [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
Jean-Michel Trivi54392232011-05-24 15:53:33 -070029#include <cutils/bitops.h>
30
31#include <system/audio.h>
32
Glenn Kasten490909d2011-12-15 09:52:39 -080033#include <audio_utils/primitives.h>
34
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035#include "AudioMixer.h"
36
37namespace android {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39// ----------------------------------------------------------------------------
40
41AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
42 : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)
43{
44 mState.enabledTracks= 0;
45 mState.needsChanged = 0;
46 mState.frameCount = frameCount;
47 mState.outputTemp = 0;
48 mState.resampleTemp = 0;
49 mState.hook = process__nop;
50 track_t* t = mState.tracks;
51 for (int i=0 ; i<32 ; i++) {
52 t->needs = 0;
53 t->volume[0] = UNITY_GAIN;
54 t->volume[1] = UNITY_GAIN;
55 t->volumeInc[0] = 0;
56 t->volumeInc[1] = 0;
Eric Laurent65b65452010-06-01 23:49:17 -070057 t->auxLevel = 0;
58 t->auxInc = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 t->channelCount = 2;
60 t->enabled = 0;
61 t->format = 16;
Jean-Michel Trivi54392232011-05-24 15:53:33 -070062 t->channelMask = AUDIO_CHANNEL_OUT_STEREO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 t->buffer.raw = 0;
64 t->bufferProvider = 0;
65 t->hook = 0;
66 t->resampler = 0;
67 t->sampleRate = mSampleRate;
68 t->in = 0;
Eric Laurent65b65452010-06-01 23:49:17 -070069 t->mainBuffer = NULL;
70 t->auxBuffer = NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 t++;
72 }
73}
74
75 AudioMixer::~AudioMixer()
76 {
77 track_t* t = mState.tracks;
78 for (int i=0 ; i<32 ; i++) {
79 delete t->resampler;
80 t++;
81 }
82 delete [] mState.outputTemp;
83 delete [] mState.resampleTemp;
84 }
85
86 int AudioMixer::getTrackName()
87 {
88 uint32_t names = mTrackNames;
89 uint32_t mask = 1;
90 int n = 0;
91 while (names & mask) {
92 mask <<= 1;
93 n++;
94 }
95 if (mask) {
Steve Block71f2cf12011-10-20 11:56:00 +010096 ALOGV("add track (%d)", n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 mTrackNames |= mask;
98 return TRACK0 + n;
99 }
100 return -1;
101 }
102
103 void AudioMixer::invalidateState(uint32_t mask)
104 {
105 if (mask) {
106 mState.needsChanged |= mask;
107 mState.hook = process__validate;
108 }
109 }
110
111 void AudioMixer::deleteTrackName(int name)
112 {
113 name -= TRACK0;
114 if (uint32_t(name) < MAX_NUM_TRACKS) {
Steve Block71f2cf12011-10-20 11:56:00 +0100115 ALOGV("deleteTrackName(%d)", name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 track_t& track(mState.tracks[ name ]);
117 if (track.enabled != 0) {
118 track.enabled = 0;
119 invalidateState(1<<name);
120 }
121 if (track.resampler) {
122 // delete the resampler
123 delete track.resampler;
124 track.resampler = 0;
125 track.sampleRate = mSampleRate;
126 invalidateState(1<<name);
127 }
128 track.volumeInc[0] = 0;
129 track.volumeInc[1] = 0;
130 mTrackNames &= ~(1<<name);
131 }
132 }
133
134status_t AudioMixer::enable(int name)
135{
136 switch (name) {
137 case MIXING: {
138 if (mState.tracks[ mActiveTrack ].enabled != 1) {
139 mState.tracks[ mActiveTrack ].enabled = 1;
Steve Block71f2cf12011-10-20 11:56:00 +0100140 ALOGV("enable(%d)", mActiveTrack);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 invalidateState(1<<mActiveTrack);
142 }
143 } break;
144 default:
145 return NAME_NOT_FOUND;
146 }
147 return NO_ERROR;
148}
149
150status_t AudioMixer::disable(int name)
151{
152 switch (name) {
153 case MIXING: {
154 if (mState.tracks[ mActiveTrack ].enabled != 0) {
155 mState.tracks[ mActiveTrack ].enabled = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100156 ALOGV("disable(%d)", mActiveTrack);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 invalidateState(1<<mActiveTrack);
158 }
159 } break;
160 default:
161 return NAME_NOT_FOUND;
162 }
163 return NO_ERROR;
164}
165
166status_t AudioMixer::setActiveTrack(int track)
167{
168 if (uint32_t(track-TRACK0) >= MAX_NUM_TRACKS) {
169 return BAD_VALUE;
170 }
171 mActiveTrack = track - TRACK0;
172 return NO_ERROR;
173}
174
Eric Laurent65b65452010-06-01 23:49:17 -0700175status_t AudioMixer::setParameter(int target, int name, void *value)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176{
Eric Laurent65b65452010-06-01 23:49:17 -0700177 int valueInt = (int)value;
178 int32_t *valueBuf = (int32_t *)value;
179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 switch (target) {
181 case TRACK:
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700182 if (name == CHANNEL_MASK) {
183 uint32_t mask = (uint32_t)value;
184 if (mState.tracks[ mActiveTrack ].channelMask != mask) {
185 uint8_t channelCount = popcount(mask);
186 if ((channelCount <= MAX_NUM_CHANNELS) && (channelCount)) {
187 mState.tracks[ mActiveTrack ].channelMask = mask;
188 mState.tracks[ mActiveTrack ].channelCount = channelCount;
Steve Block71f2cf12011-10-20 11:56:00 +0100189 ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", mask);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 invalidateState(1<<mActiveTrack);
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700191 return NO_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 }
Jean-Michel Trivi54392232011-05-24 15:53:33 -0700193 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 return NO_ERROR;
195 }
196 }
Eric Laurent65b65452010-06-01 23:49:17 -0700197 if (name == MAIN_BUFFER) {
198 if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) {
199 mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
Steve Block71f2cf12011-10-20 11:56:00 +0100200 ALOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
Eric Laurent65b65452010-06-01 23:49:17 -0700201 invalidateState(1<<mActiveTrack);
202 }
203 return NO_ERROR;
204 }
205 if (name == AUX_BUFFER) {
206 if (mState.tracks[ mActiveTrack ].auxBuffer != valueBuf) {
207 mState.tracks[ mActiveTrack ].auxBuffer = valueBuf;
Steve Block71f2cf12011-10-20 11:56:00 +0100208 ALOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf);
Eric Laurent65b65452010-06-01 23:49:17 -0700209 invalidateState(1<<mActiveTrack);
210 }
211 return NO_ERROR;
212 }
213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 break;
215 case RESAMPLE:
216 if (name == SAMPLE_RATE) {
Eric Laurent65b65452010-06-01 23:49:17 -0700217 if (valueInt > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 track_t& track = mState.tracks[ mActiveTrack ];
Eric Laurent65b65452010-06-01 23:49:17 -0700219 if (track.setResampler(uint32_t(valueInt), mSampleRate)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100220 ALOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
Eric Laurent65b65452010-06-01 23:49:17 -0700221 uint32_t(valueInt));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 invalidateState(1<<mActiveTrack);
223 }
224 return NO_ERROR;
225 }
226 }
Eric Laurent4bb21c42011-02-28 16:52:51 -0800227 if (name == RESET) {
228 track_t& track = mState.tracks[ mActiveTrack ];
229 track.resetResampler();
230 invalidateState(1<<mActiveTrack);
231 return NO_ERROR;
232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 break;
234 case RAMP_VOLUME:
235 case VOLUME:
236 if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
237 track_t& track = mState.tracks[ mActiveTrack ];
Eric Laurent65b65452010-06-01 23:49:17 -0700238 if (track.volume[name-VOLUME0] != valueInt) {
Steve Block71f2cf12011-10-20 11:56:00 +0100239 ALOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
Eric Laurent65b65452010-06-01 23:49:17 -0700241 track.volume[name-VOLUME0] = valueInt;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 if (target == VOLUME) {
Eric Laurent65b65452010-06-01 23:49:17 -0700243 track.prevVolume[name-VOLUME0] = valueInt << 16;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 track.volumeInc[name-VOLUME0] = 0;
245 } else {
Eric Laurent65b65452010-06-01 23:49:17 -0700246 int32_t d = (valueInt<<16) - track.prevVolume[name-VOLUME0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 int32_t volInc = d / int32_t(mState.frameCount);
248 track.volumeInc[name-VOLUME0] = volInc;
249 if (volInc == 0) {
Eric Laurent65b65452010-06-01 23:49:17 -0700250 track.prevVolume[name-VOLUME0] = valueInt << 16;
251 }
252 }
253 invalidateState(1<<mActiveTrack);
254 }
255 return NO_ERROR;
256 } else if (name == AUXLEVEL) {
257 track_t& track = mState.tracks[ mActiveTrack ];
258 if (track.auxLevel != valueInt) {
Steve Block71f2cf12011-10-20 11:56:00 +0100259 ALOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt);
Eric Laurent65b65452010-06-01 23:49:17 -0700260 track.prevAuxLevel = track.auxLevel << 16;
261 track.auxLevel = valueInt;
262 if (target == VOLUME) {
263 track.prevAuxLevel = valueInt << 16;
264 track.auxInc = 0;
265 } else {
266 int32_t d = (valueInt<<16) - track.prevAuxLevel;
267 int32_t volInc = d / int32_t(mState.frameCount);
268 track.auxInc = volInc;
269 if (volInc == 0) {
270 track.prevAuxLevel = valueInt << 16;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 }
272 }
273 invalidateState(1<<mActiveTrack);
274 }
275 return NO_ERROR;
276 }
277 break;
278 }
279 return BAD_VALUE;
280}
281
282bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
283{
284 if (value!=devSampleRate || resampler) {
285 if (sampleRate != value) {
286 sampleRate = value;
287 if (resampler == 0) {
288 resampler = AudioResampler::create(
289 format, channelCount, devSampleRate);
290 }
291 return true;
292 }
293 }
294 return false;
295}
296
297bool AudioMixer::track_t::doesResample() const
298{
299 return resampler != 0;
300}
301
Eric Laurent4bb21c42011-02-28 16:52:51 -0800302void AudioMixer::track_t::resetResampler()
303{
304 if (resampler != 0) {
305 resampler->reset();
306 }
307}
308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309inline
Eric Laurent65b65452010-06-01 23:49:17 -0700310void AudioMixer::track_t::adjustVolumeRamp(bool aux)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311{
312 for (int i=0 ; i<2 ; i++) {
313 if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
314 ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
315 volumeInc[i] = 0;
316 prevVolume[i] = volume[i]<<16;
317 }
318 }
Eric Laurent65b65452010-06-01 23:49:17 -0700319 if (aux) {
320 if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) ||
321 ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) {
322 auxInc = 0;
323 prevAuxLevel = auxLevel<<16;
324 }
325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326}
327
328
329status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
330{
331 mState.tracks[ mActiveTrack ].bufferProvider = buffer;
332 return NO_ERROR;
333}
334
335
336
Eric Laurent65b65452010-06-01 23:49:17 -0700337void AudioMixer::process()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338{
Eric Laurent65b65452010-06-01 23:49:17 -0700339 mState.hook(&mState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340}
341
342
Eric Laurent65b65452010-06-01 23:49:17 -0700343void AudioMixer::process__validate(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344{
345 LOGW_IF(!state->needsChanged,
346 "in process__validate() but nothing's invalid");
347
348 uint32_t changed = state->needsChanged;
349 state->needsChanged = 0; // clear the validation flag
350
351 // recompute which tracks are enabled / disabled
352 uint32_t enabled = 0;
353 uint32_t disabled = 0;
354 while (changed) {
355 const int i = 31 - __builtin_clz(changed);
356 const uint32_t mask = 1<<i;
357 changed &= ~mask;
358 track_t& t = state->tracks[i];
359 (t.enabled ? enabled : disabled) |= mask;
360 }
361 state->enabledTracks &= ~disabled;
362 state->enabledTracks |= enabled;
363
364 // compute everything we need...
365 int countActiveTracks = 0;
366 int all16BitsStereoNoResample = 1;
367 int resampling = 0;
368 int volumeRamp = 0;
369 uint32_t en = state->enabledTracks;
370 while (en) {
371 const int i = 31 - __builtin_clz(en);
372 en &= ~(1<<i);
373
374 countActiveTracks++;
375 track_t& t = state->tracks[i];
376 uint32_t n = 0;
377 n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
378 n |= NEEDS_FORMAT_16;
379 n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
Eric Laurent65b65452010-06-01 23:49:17 -0700380 if (t.auxLevel != 0 && t.auxBuffer != NULL) {
381 n |= NEEDS_AUX_ENABLED;
382 }
383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 if (t.volumeInc[0]|t.volumeInc[1]) {
385 volumeRamp = 1;
386 } else if (!t.doesResample() && t.volumeRL == 0) {
387 n |= NEEDS_MUTE_ENABLED;
388 }
389 t.needs = n;
390
391 if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
392 t.hook = track__nop;
393 } else {
Eric Laurent65b65452010-06-01 23:49:17 -0700394 if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
395 all16BitsStereoNoResample = 0;
396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
398 all16BitsStereoNoResample = 0;
399 resampling = 1;
400 t.hook = track__genericResample;
401 } else {
402 if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
403 t.hook = track__16BitsMono;
404 all16BitsStereoNoResample = 0;
405 }
406 if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){
407 t.hook = track__16BitsStereo;
408 }
409 }
410 }
411 }
412
413 // select the processing hooks
414 state->hook = process__nop;
415 if (countActiveTracks) {
416 if (resampling) {
417 if (!state->outputTemp) {
418 state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
419 }
420 if (!state->resampleTemp) {
421 state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
422 }
423 state->hook = process__genericResampling;
424 } else {
425 if (state->outputTemp) {
426 delete [] state->outputTemp;
427 state->outputTemp = 0;
428 }
429 if (state->resampleTemp) {
430 delete [] state->resampleTemp;
431 state->resampleTemp = 0;
432 }
433 state->hook = process__genericNoResampling;
434 if (all16BitsStereoNoResample && !volumeRamp) {
435 if (countActiveTracks == 1) {
436 state->hook = process__OneTrack16BitsStereoNoResampling;
437 }
438 }
439 }
440 }
441
Steve Block71f2cf12011-10-20 11:56:00 +0100442 ALOGV("mixer configuration change: %d activeTracks (%08x) "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d",
444 countActiveTracks, state->enabledTracks,
445 all16BitsStereoNoResample, resampling, volumeRamp);
446
Eric Laurent65b65452010-06-01 23:49:17 -0700447 state->hook(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448
449 // Now that the volume ramp has been done, set optimal state and
450 // track hooks for subsequent mixer process
451 if (countActiveTracks) {
452 int allMuted = 1;
453 uint32_t en = state->enabledTracks;
454 while (en) {
455 const int i = 31 - __builtin_clz(en);
456 en &= ~(1<<i);
457 track_t& t = state->tracks[i];
458 if (!t.doesResample() && t.volumeRL == 0)
459 {
460 t.needs |= NEEDS_MUTE_ENABLED;
461 t.hook = track__nop;
462 } else {
463 allMuted = 0;
464 }
465 }
466 if (allMuted) {
467 state->hook = process__nop;
Eric Laurent65b65452010-06-01 23:49:17 -0700468 } else if (all16BitsStereoNoResample) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 if (countActiveTracks == 1) {
470 state->hook = process__OneTrack16BitsStereoNoResampling;
471 }
472 }
473 }
474}
475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476
Eric Laurent65b65452010-06-01 23:49:17 -0700477void 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 -0800478{
479 t->resampler->setSampleRate(t->sampleRate);
480
481 // ramp gain - resample to temp buffer and scale/mix in 2nd step
Eric Laurent65b65452010-06-01 23:49:17 -0700482 if (aux != NULL) {
483 // always resample with unity gain when sending to auxiliary buffer to be able
484 // to apply send level after resampling
485 // TODO: modify each resampler to support aux channel?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
487 memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
488 t->resampler->resample(temp, outFrameCount, t->bufferProvider);
Eric Laurent65b65452010-06-01 23:49:17 -0700489 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
490 volumeRampStereo(t, out, outFrameCount, temp, aux);
491 } else {
492 volumeStereo(t, out, outFrameCount, temp, aux);
493 }
494 } else {
495 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
496 t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
497 memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
498 t->resampler->resample(temp, outFrameCount, t->bufferProvider);
499 volumeRampStereo(t, out, outFrameCount, temp, aux);
500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501
Eric Laurent65b65452010-06-01 23:49:17 -0700502 // constant gain
503 else {
504 t->resampler->setVolume(t->volume[0], t->volume[1]);
505 t->resampler->resample(out, outFrameCount, t->bufferProvider);
506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 }
508}
509
Eric Laurent65b65452010-06-01 23:49:17 -0700510void 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 -0800511{
512}
513
Eric Laurent65b65452010-06-01 23:49:17 -0700514void 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 -0800515{
516 int32_t vl = t->prevVolume[0];
517 int32_t vr = t->prevVolume[1];
518 const int32_t vlInc = t->volumeInc[0];
519 const int32_t vrInc = t->volumeInc[1];
520
521 //LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
522 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
523 // (vl + vlInc*frameCount)/65536.0f, frameCount);
Eric Laurent65b65452010-06-01 23:49:17 -0700524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 // ramp volume
Eric Laurent65b65452010-06-01 23:49:17 -0700526 if UNLIKELY(aux != NULL) {
527 int32_t va = t->prevAuxLevel;
528 const int32_t vaInc = t->auxInc;
529 int32_t l;
530 int32_t r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531
532 do {
Eric Laurent65b65452010-06-01 23:49:17 -0700533 l = (*temp++ >> 12);
534 r = (*temp++ >> 12);
535 *out++ += (vl >> 16) * l;
536 *out++ += (vr >> 16) * r;
537 *aux++ += (va >> 17) * (l + r);
538 vl += vlInc;
539 vr += vrInc;
540 va += vaInc;
541 } while (--frameCount);
542 t->prevAuxLevel = va;
543 } else {
544 do {
545 *out++ += (vl >> 16) * (*temp++ >> 12);
546 *out++ += (vr >> 16) * (*temp++ >> 12);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 vl += vlInc;
548 vr += vrInc;
549 } while (--frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 }
Eric Laurent65b65452010-06-01 23:49:17 -0700551 t->prevVolume[0] = vl;
552 t->prevVolume[1] = vr;
553 t->adjustVolumeRamp((aux != NULL));
554}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555
Eric Laurent65b65452010-06-01 23:49:17 -0700556void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
557{
558 const int16_t vl = t->volume[0];
559 const int16_t vr = t->volume[1];
560
561 if UNLIKELY(aux != NULL) {
562 const int16_t va = (int16_t)t->auxLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 do {
Eric Laurent65b65452010-06-01 23:49:17 -0700564 int16_t l = (int16_t)(*temp++ >> 12);
565 int16_t r = (int16_t)(*temp++ >> 12);
566 out[0] = mulAdd(l, vl, out[0]);
567 int16_t a = (int16_t)(((int32_t)l + r) >> 1);
568 out[1] = mulAdd(r, vr, out[1]);
569 out += 2;
570 aux[0] = mulAdd(a, va, aux[0]);
571 aux++;
572 } while (--frameCount);
573 } else {
574 do {
575 int16_t l = (int16_t)(*temp++ >> 12);
576 int16_t r = (int16_t)(*temp++ >> 12);
577 out[0] = mulAdd(l, vl, out[0]);
578 out[1] = mulAdd(r, vr, out[1]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 out += 2;
580 } while (--frameCount);
581 }
Eric Laurent65b65452010-06-01 23:49:17 -0700582}
583
584void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
585{
586 int16_t const *in = static_cast<int16_t const *>(t->in);
587
588 if UNLIKELY(aux != NULL) {
589 int32_t l;
590 int32_t r;
591 // ramp gain
592 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
593 int32_t vl = t->prevVolume[0];
594 int32_t vr = t->prevVolume[1];
595 int32_t va = t->prevAuxLevel;
596 const int32_t vlInc = t->volumeInc[0];
597 const int32_t vrInc = t->volumeInc[1];
598 const int32_t vaInc = t->auxInc;
599 // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
600 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
601 // (vl + vlInc*frameCount)/65536.0f, frameCount);
602
603 do {
604 l = (int32_t)*in++;
605 r = (int32_t)*in++;
606 *out++ += (vl >> 16) * l;
607 *out++ += (vr >> 16) * r;
608 *aux++ += (va >> 17) * (l + r);
609 vl += vlInc;
610 vr += vrInc;
611 va += vaInc;
612 } while (--frameCount);
613
614 t->prevVolume[0] = vl;
615 t->prevVolume[1] = vr;
616 t->prevAuxLevel = va;
617 t->adjustVolumeRamp(true);
618 }
619
620 // constant gain
621 else {
622 const uint32_t vrl = t->volumeRL;
623 const int16_t va = (int16_t)t->auxLevel;
624 do {
625 uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
626 int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1);
627 in += 2;
628 out[0] = mulAddRL(1, rl, vrl, out[0]);
629 out[1] = mulAddRL(0, rl, vrl, out[1]);
630 out += 2;
631 aux[0] = mulAdd(a, va, aux[0]);
632 aux++;
633 } while (--frameCount);
634 }
635 } else {
636 // ramp gain
637 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
638 int32_t vl = t->prevVolume[0];
639 int32_t vr = t->prevVolume[1];
640 const int32_t vlInc = t->volumeInc[0];
641 const int32_t vrInc = t->volumeInc[1];
642
643 // LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
644 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
645 // (vl + vlInc*frameCount)/65536.0f, frameCount);
646
647 do {
648 *out++ += (vl >> 16) * (int32_t) *in++;
649 *out++ += (vr >> 16) * (int32_t) *in++;
650 vl += vlInc;
651 vr += vrInc;
652 } while (--frameCount);
653
654 t->prevVolume[0] = vl;
655 t->prevVolume[1] = vr;
656 t->adjustVolumeRamp(false);
657 }
658
659 // constant gain
660 else {
661 const uint32_t vrl = t->volumeRL;
662 do {
663 uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
664 in += 2;
665 out[0] = mulAddRL(1, rl, vrl, out[0]);
666 out[1] = mulAddRL(0, rl, vrl, out[1]);
667 out += 2;
668 } while (--frameCount);
669 }
670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 t->in = in;
672}
673
Eric Laurent65b65452010-06-01 23:49:17 -0700674void 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 -0800675{
676 int16_t const *in = static_cast<int16_t const *>(t->in);
677
Eric Laurent65b65452010-06-01 23:49:17 -0700678 if UNLIKELY(aux != NULL) {
679 // ramp gain
680 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
681 int32_t vl = t->prevVolume[0];
682 int32_t vr = t->prevVolume[1];
683 int32_t va = t->prevAuxLevel;
684 const int32_t vlInc = t->volumeInc[0];
685 const int32_t vrInc = t->volumeInc[1];
686 const int32_t vaInc = t->auxInc;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687
Eric Laurent65b65452010-06-01 23:49:17 -0700688 // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
689 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
690 // (vl + vlInc*frameCount)/65536.0f, frameCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691
Eric Laurent65b65452010-06-01 23:49:17 -0700692 do {
693 int32_t l = *in++;
694 *out++ += (vl >> 16) * l;
695 *out++ += (vr >> 16) * l;
696 *aux++ += (va >> 16) * l;
697 vl += vlInc;
698 vr += vrInc;
699 va += vaInc;
700 } while (--frameCount);
701
702 t->prevVolume[0] = vl;
703 t->prevVolume[1] = vr;
704 t->prevAuxLevel = va;
705 t->adjustVolumeRamp(true);
706 }
707 // constant gain
708 else {
709 const int16_t vl = t->volume[0];
710 const int16_t vr = t->volume[1];
711 const int16_t va = (int16_t)t->auxLevel;
712 do {
713 int16_t l = *in++;
714 out[0] = mulAdd(l, vl, out[0]);
715 out[1] = mulAdd(l, vr, out[1]);
716 out += 2;
717 aux[0] = mulAdd(l, va, aux[0]);
718 aux++;
719 } while (--frameCount);
720 }
721 } else {
722 // ramp gain
723 if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
724 int32_t vl = t->prevVolume[0];
725 int32_t vr = t->prevVolume[1];
726 const int32_t vlInc = t->volumeInc[0];
727 const int32_t vrInc = t->volumeInc[1];
728
729 // LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
730 // t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
731 // (vl + vlInc*frameCount)/65536.0f, frameCount);
732
733 do {
734 int32_t l = *in++;
735 *out++ += (vl >> 16) * l;
736 *out++ += (vr >> 16) * l;
737 vl += vlInc;
738 vr += vrInc;
739 } while (--frameCount);
740
741 t->prevVolume[0] = vl;
742 t->prevVolume[1] = vr;
743 t->adjustVolumeRamp(false);
744 }
745 // constant gain
746 else {
747 const int16_t vl = t->volume[0];
748 const int16_t vr = t->volume[1];
749 do {
750 int16_t l = *in++;
751 out[0] = mulAdd(l, vl, out[0]);
752 out[1] = mulAdd(l, vr, out[1]);
753 out += 2;
754 } while (--frameCount);
755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 }
757 t->in = in;
758}
759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760// no-op case
Eric Laurent65b65452010-06-01 23:49:17 -0700761void AudioMixer::process__nop(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762{
Eric Laurent65b65452010-06-01 23:49:17 -0700763 uint32_t e0 = state->enabledTracks;
764 size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
765 while (e0) {
766 // process by group of tracks with same output buffer to
767 // avoid multiple memset() on same buffer
768 uint32_t e1 = e0, e2 = e0;
769 int i = 31 - __builtin_clz(e1);
770 track_t& t1 = state->tracks[i];
771 e2 &= ~(1<<i);
772 while (e2) {
773 i = 31 - __builtin_clz(e2);
774 e2 &= ~(1<<i);
775 track_t& t2 = state->tracks[i];
776 if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
777 e1 &= ~(1<<i);
778 }
779 }
780 e0 &= ~(e1);
781
782 memset(t1.mainBuffer, 0, bufSize);
783
784 while (e1) {
785 i = 31 - __builtin_clz(e1);
786 e1 &= ~(1<<i);
787 t1 = state->tracks[i];
788 size_t outFrames = state->frameCount;
789 while (outFrames) {
790 t1.buffer.frameCount = outFrames;
791 t1.bufferProvider->getNextBuffer(&t1.buffer);
792 if (!t1.buffer.raw) break;
793 outFrames -= t1.buffer.frameCount;
794 t1.bufferProvider->releaseBuffer(&t1.buffer);
795 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 }
797 }
798}
799
800// generic code without resampling
Eric Laurent65b65452010-06-01 23:49:17 -0700801void AudioMixer::process__genericNoResampling(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802{
803 int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
804
805 // acquire each track's buffer
806 uint32_t enabledTracks = state->enabledTracks;
Eric Laurent65b65452010-06-01 23:49:17 -0700807 uint32_t e0 = enabledTracks;
808 while (e0) {
809 const int i = 31 - __builtin_clz(e0);
810 e0 &= ~(1<<i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 track_t& t = state->tracks[i];
812 t.buffer.frameCount = state->frameCount;
813 t.bufferProvider->getNextBuffer(&t.buffer);
814 t.frameCount = t.buffer.frameCount;
815 t.in = t.buffer.raw;
816 // t.in == NULL can happen if the track was flushed just after having
817 // been enabled for mixing.
818 if (t.in == NULL)
819 enabledTracks &= ~(1<<i);
820 }
821
Eric Laurent65b65452010-06-01 23:49:17 -0700822 e0 = enabledTracks;
823 while (e0) {
824 // process by group of tracks with same output buffer to
825 // optimize cache use
826 uint32_t e1 = e0, e2 = e0;
827 int j = 31 - __builtin_clz(e1);
828 track_t& t1 = state->tracks[j];
829 e2 &= ~(1<<j);
830 while (e2) {
831 j = 31 - __builtin_clz(e2);
832 e2 &= ~(1<<j);
833 track_t& t2 = state->tracks[j];
834 if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
835 e1 &= ~(1<<j);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 }
837 }
Eric Laurent65b65452010-06-01 23:49:17 -0700838 e0 &= ~(e1);
839 // this assumes output 16 bits stereo, no resampling
840 int32_t *out = t1.mainBuffer;
841 size_t numFrames = 0;
842 do {
843 memset(outTemp, 0, sizeof(outTemp));
844 e2 = e1;
845 while (e2) {
846 const int i = 31 - __builtin_clz(e2);
847 e2 &= ~(1<<i);
848 track_t& t = state->tracks[i];
849 size_t outFrames = BLOCKSIZE;
850 int32_t *aux = NULL;
851 if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
852 aux = t.auxBuffer + numFrames;
853 }
854 while (outFrames) {
855 size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
856 if (inFrames) {
857 (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
858 t.frameCount -= inFrames;
859 outFrames -= inFrames;
860 if UNLIKELY(aux != NULL) {
861 aux += inFrames;
862 }
863 }
864 if (t.frameCount == 0 && outFrames) {
865 t.bufferProvider->releaseBuffer(&t.buffer);
866 t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
867 t.bufferProvider->getNextBuffer(&t.buffer);
868 t.in = t.buffer.raw;
869 if (t.in == NULL) {
870 enabledTracks &= ~(1<<i);
871 e1 &= ~(1<<i);
872 break;
873 }
874 t.frameCount = t.buffer.frameCount;
875 }
876 }
877 }
878 ditherAndClamp(out, outTemp, BLOCKSIZE);
879 out += BLOCKSIZE;
880 numFrames += BLOCKSIZE;
881 } while (numFrames < state->frameCount);
882 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883
884 // release each track's buffer
Eric Laurent65b65452010-06-01 23:49:17 -0700885 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.bufferProvider->releaseBuffer(&t.buffer);
891 }
892}
893
Eric Laurent65b65452010-06-01 23:49:17 -0700894
895 // generic code with resampling
896void AudioMixer::process__genericResampling(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897{
898 int32_t* const outTemp = state->outputTemp;
899 const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 size_t numFrames = state->frameCount;
902
Eric Laurent65b65452010-06-01 23:49:17 -0700903 uint32_t e0 = state->enabledTracks;
904 while (e0) {
905 // process by group of tracks with same output buffer
906 // to optimize cache use
907 uint32_t e1 = e0, e2 = e0;
908 int j = 31 - __builtin_clz(e1);
909 track_t& t1 = state->tracks[j];
910 e2 &= ~(1<<j);
911 while (e2) {
912 j = 31 - __builtin_clz(e2);
913 e2 &= ~(1<<j);
914 track_t& t2 = state->tracks[j];
915 if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
916 e1 &= ~(1<<j);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 }
918 }
Eric Laurent65b65452010-06-01 23:49:17 -0700919 e0 &= ~(e1);
920 int32_t *out = t1.mainBuffer;
Yuuhi Yamaguchi681d8182011-02-04 15:24:34 +0100921 memset(outTemp, 0, size);
Eric Laurent65b65452010-06-01 23:49:17 -0700922 while (e1) {
923 const int i = 31 - __builtin_clz(e1);
924 e1 &= ~(1<<i);
925 track_t& t = state->tracks[i];
926 int32_t *aux = NULL;
927 if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
928 aux = t.auxBuffer;
929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930
Eric Laurent65b65452010-06-01 23:49:17 -0700931 // this is a little goofy, on the resampling case we don't
932 // acquire/release the buffers because it's done by
933 // the resampler.
934 if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
935 (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
936 } else {
937
938 size_t outFrames = 0;
939
940 while (outFrames < numFrames) {
941 t.buffer.frameCount = numFrames - outFrames;
942 t.bufferProvider->getNextBuffer(&t.buffer);
943 t.in = t.buffer.raw;
944 // t.in == NULL can happen if the track was flushed just after having
945 // been enabled for mixing.
946 if (t.in == NULL) break;
947
948 if UNLIKELY(aux != NULL) {
949 aux += outFrames;
950 }
951 (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
952 outFrames += t.buffer.frameCount;
953 t.bufferProvider->releaseBuffer(&t.buffer);
954 }
955 }
956 }
957 ditherAndClamp(out, outTemp, numFrames);
958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959}
960
961// one track, 16 bits stereo without resampling is the most common case
Eric Laurent65b65452010-06-01 23:49:17 -0700962void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963{
964 const int i = 31 - __builtin_clz(state->enabledTracks);
965 const track_t& t = state->tracks[i];
966
967 AudioBufferProvider::Buffer& b(t.buffer);
Eric Laurent65b65452010-06-01 23:49:17 -0700968
969 int32_t* out = t.mainBuffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 size_t numFrames = state->frameCount;
Eric Laurent65b65452010-06-01 23:49:17 -0700971
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 const int16_t vl = t.volume[0];
973 const int16_t vr = t.volume[1];
974 const uint32_t vrl = t.volumeRL;
975 while (numFrames) {
976 b.frameCount = numFrames;
977 t.bufferProvider->getNextBuffer(&b);
978 int16_t const *in = b.i16;
979
980 // in == NULL can happen if the track was flushed just after having
981 // been enabled for mixing.
The Android Open Source Project10592532009-03-18 17:39:46 -0700982 if (in == NULL || ((unsigned long)in & 3)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
The Android Open Source Project10592532009-03-18 17:39:46 -0700984 LOGE_IF(((unsigned long)in & 3), "process stereo track: input buffer alignment pb: buffer %p track %d, channels %d, needs %08x",
985 in, i, t.channelCount, t.needs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 return;
987 }
988 size_t outFrames = b.frameCount;
Eric Laurent65b65452010-06-01 23:49:17 -0700989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
991 // volume is boosted, so we might need to clamp even though
992 // we process only one track.
993 do {
994 uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
995 in += 2;
996 int32_t l = mulRL(1, rl, vrl) >> 12;
997 int32_t r = mulRL(0, rl, vrl) >> 12;
998 // clamping...
999 l = clamp16(l);
1000 r = clamp16(r);
1001 *out++ = (r<<16) | (l & 0xFFFF);
1002 } while (--outFrames);
1003 } else {
1004 do {
1005 uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
1006 in += 2;
1007 int32_t l = mulRL(1, rl, vrl) >> 12;
1008 int32_t r = mulRL(0, rl, vrl) >> 12;
1009 *out++ = (r<<16) | (l & 0xFFFF);
1010 } while (--outFrames);
1011 }
1012 numFrames -= b.frameCount;
1013 t.bufferProvider->releaseBuffer(&b);
1014 }
1015}
1016
1017// 2 tracks is also a common case
Eric Laurent65b65452010-06-01 23:49:17 -07001018// NEVER used in current implementation of process__validate()
1019// only use if the 2 tracks have the same output buffer
1020void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021{
1022 int i;
1023 uint32_t en = state->enabledTracks;
1024
1025 i = 31 - __builtin_clz(en);
1026 const track_t& t0 = state->tracks[i];
1027 AudioBufferProvider::Buffer& b0(t0.buffer);
1028
1029 en &= ~(1<<i);
1030 i = 31 - __builtin_clz(en);
1031 const track_t& t1 = state->tracks[i];
1032 AudioBufferProvider::Buffer& b1(t1.buffer);
Eric Laurent65b65452010-06-01 23:49:17 -07001033
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 int16_t const *in0;
1035 const int16_t vl0 = t0.volume[0];
1036 const int16_t vr0 = t0.volume[1];
1037 size_t frameCount0 = 0;
Eric Laurent65b65452010-06-01 23:49:17 -07001038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 int16_t const *in1;
1040 const int16_t vl1 = t1.volume[0];
1041 const int16_t vr1 = t1.volume[1];
1042 size_t frameCount1 = 0;
Eric Laurent65b65452010-06-01 23:49:17 -07001043
1044 //FIXME: only works if two tracks use same buffer
1045 int32_t* out = t0.mainBuffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 size_t numFrames = state->frameCount;
1047 int16_t const *buff = NULL;
1048
Eric Laurent65b65452010-06-01 23:49:17 -07001049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 while (numFrames) {
Eric Laurent65b65452010-06-01 23:49:17 -07001051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 if (frameCount0 == 0) {
1053 b0.frameCount = numFrames;
1054 t0.bufferProvider->getNextBuffer(&b0);
1055 if (b0.i16 == NULL) {
1056 if (buff == NULL) {
1057 buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
1058 }
1059 in0 = buff;
1060 b0.frameCount = numFrames;
1061 } else {
1062 in0 = b0.i16;
1063 }
1064 frameCount0 = b0.frameCount;
1065 }
1066 if (frameCount1 == 0) {
1067 b1.frameCount = numFrames;
1068 t1.bufferProvider->getNextBuffer(&b1);
1069 if (b1.i16 == NULL) {
1070 if (buff == NULL) {
1071 buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
1072 }
1073 in1 = buff;
1074 b1.frameCount = numFrames;
1075 } else {
1076 in1 = b1.i16;
1077 }
1078 frameCount1 = b1.frameCount;
1079 }
Eric Laurent65b65452010-06-01 23:49:17 -07001080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
1082
1083 numFrames -= outFrames;
1084 frameCount0 -= outFrames;
1085 frameCount1 -= outFrames;
Eric Laurent65b65452010-06-01 23:49:17 -07001086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 do {
1088 int32_t l0 = *in0++;
1089 int32_t r0 = *in0++;
1090 l0 = mul(l0, vl0);
1091 r0 = mul(r0, vr0);
1092 int32_t l = *in1++;
1093 int32_t r = *in1++;
1094 l = mulAdd(l, vl1, l0) >> 12;
1095 r = mulAdd(r, vr1, r0) >> 12;
1096 // clamping...
1097 l = clamp16(l);
1098 r = clamp16(r);
1099 *out++ = (r<<16) | (l & 0xFFFF);
1100 } while (--outFrames);
Eric Laurent65b65452010-06-01 23:49:17 -07001101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 if (frameCount0 == 0) {
1103 t0.bufferProvider->releaseBuffer(&b0);
1104 }
1105 if (frameCount1 == 0) {
1106 t1.bufferProvider->releaseBuffer(&b1);
1107 }
Eric Laurent65b65452010-06-01 23:49:17 -07001108 }
1109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 if (buff != NULL) {
Eric Laurent65b65452010-06-01 23:49:17 -07001111 delete [] buff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 }
1113}
1114
1115// ----------------------------------------------------------------------------
1116}; // namespace android
1117