104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*
204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Copyright (C) 2012 The Android Open Source Project
304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * you may not use this file except in compliance with the License.
604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * You may obtain a copy of the License at
704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
1004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
1104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
1204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * See the License for the specific language governing permissions and
1404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * limitations under the License.
1504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
1604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
1704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi#define LOG_TAG "EffectDownmix"
18f28c8792f64e10c3c477d86bf4804a8566ff524eJean-Michel Trivi//#define LOG_NDEBUG 0
1904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi#include <cutils/log.h>
2004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi#include <stdlib.h>
2104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi#include <string.h>
2204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi#include <stdbool.h>
2304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi#include "EffectDownmix.h"
2404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
256895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi// Do not submit with DOWNMIX_TEST_CHANNEL_INDEX defined, strictly for testing
266895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi//#define DOWNMIX_TEST_CHANNEL_INDEX 0
276895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi// Do not submit with DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER defined, strictly for testing
286895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi//#define DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER 0
296895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
3004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi#define MINUS_3_DB_IN_Q19_12 2896 // -3dB = 0.707 * 2^12 = 2896
3104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
32db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivitypedef enum {
33db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi    CHANNEL_MASK_SURROUND = AUDIO_CHANNEL_OUT_SURROUND,
34db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi    CHANNEL_MASK_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD,
35db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi    // like AUDIO_CHANNEL_OUT_QUAD with *_SIDE_* instead of *_BACK_*, same channel order
36db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi    CHANNEL_MASK_QUAD_SIDE =
37db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_FRONT_LEFT |
38db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_FRONT_RIGHT |
39db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_SIDE_LEFT |
40db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_SIDE_RIGHT,
41db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi    CHANNEL_MASK_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1,
42db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi    // like AUDIO_CHANNEL_OUT_5POINT1 with *_SIDE_* instead of *_BACK_*, same channel order
43db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi    CHANNEL_MASK_5POINT1_SIDE =
44db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_FRONT_LEFT |
45db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_FRONT_RIGHT |
46db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_FRONT_CENTER |
47db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
48db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_SIDE_LEFT |
49db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi            AUDIO_CHANNEL_OUT_SIDE_RIGHT,
50db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi    CHANNEL_MASK_7POINT1_SIDE_BACK = AUDIO_CHANNEL_OUT_7POINT1,
51db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi} downmix_input_channel_mask_t;
52db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi
5304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi// effect_handle_t interface implementation for downmix effect
5404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviconst struct effect_interface_s gDownmixInterface = {
5504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        Downmix_Process,
5604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        Downmix_Command,
5704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        Downmix_GetDescriptor,
5804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        NULL /* no process_reverse function, no reference stream needed */
5904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi};
6004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
6104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviaudio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
6204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    tag : AUDIO_EFFECT_LIBRARY_TAG,
6304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    version : EFFECT_LIBRARY_API_VERSION,
6404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    name : "Downmix Library",
6504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    implementor : "The Android Open Source Project",
6604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    query_num_effects : DownmixLib_QueryNumberEffects,
6704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    query_effect : DownmixLib_QueryEffect,
6804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    create_effect : DownmixLib_Create,
6904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    release_effect : DownmixLib_Release,
7004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    get_descriptor : DownmixLib_GetDescriptor,
7104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi};
7204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
7304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
7404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi// AOSP insert downmix UUID: 93f04452-e4fe-41cc-91f9-e475b6d1d69f
7504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivistatic const effect_descriptor_t gDownmixDescriptor = {
7604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        EFFECT_UIID_DOWNMIX__, //type
7704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        {0x93f04452, 0xe4fe, 0x41cc, 0x91f9, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}}, // uuid
7804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        EFFECT_CONTROL_API_VERSION,
7904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
8004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        0, //FIXME what value should be reported? // cpu load
8104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        0, //FIXME what value should be reported? // memory usage
8204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        "Multichannel Downmix To Stereo", // human readable effect name
8304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        "The Android Open Source Project" // human readable effect implementor name
8404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi};
8504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
8604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi// gDescriptors contains pointers to all defined effect descriptor in this library
8704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivistatic const effect_descriptor_t * const gDescriptors[] = {
8804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        &gDownmixDescriptor
8904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi};
9004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
9104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi// number of effects in this library
9204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviconst int kNbEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
9304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
9404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
9504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
966895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi * Test code
976895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *--------------------------------------------------------------------------*/
986895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi#ifdef DOWNMIX_TEST_CHANNEL_INDEX
996895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi// strictly for testing, logs the indices of the channels for a given mask,
1006895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi// uses the same code as Downmix_foldGeneric()
1016895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivivoid Downmix_testIndexComputation(uint32_t mask) {
1026895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    ALOGI("Testing index computation for 0x%x:", mask);
1036895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // check against unsupported channels
1046895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if (mask & kUnsupported) {
1056895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        ALOGE("Unsupported channels (top or front left/right of center)");
1066895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        return;
1076895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
1086895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // verify has FL/FR
1096895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if ((mask & AUDIO_CHANNEL_OUT_STEREO) != AUDIO_CHANNEL_OUT_STEREO) {
1106895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        ALOGE("Front channels must be present");
1116895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        return;
1126895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
1136895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // verify uses SIDE as a pair (ok if not using SIDE at all)
1146895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    bool hasSides = false;
1156895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if ((mask & kSides) != 0) {
1166895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        if ((mask & kSides) != kSides) {
1176895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            ALOGE("Side channels must be used as a pair");
1186895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            return;
1196895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        }
1206895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        hasSides = true;
1216895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
1226895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // verify uses BACK as a pair (ok if not using BACK at all)
1236895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    bool hasBacks = false;
1246895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if ((mask & kBacks) != 0) {
1256895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        if ((mask & kBacks) != kBacks) {
1266895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            ALOGE("Back channels must be used as a pair");
1276895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            return;
1286895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        }
1296895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        hasBacks = true;
1306895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
1316895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
1326895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int numChan = popcount(mask);
1336895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
1346895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const bool hasLFE =
1356895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
1366895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
1376895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // compute at what index each channel is: samples will be in the following order:
1386895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    //   FL FR FC LFE BL BR BC SL SR
1396895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // when a channel is not present, its index is set to the same as the index of the preceding
1406895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // channel
1416895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexFC  = hasFC    ? 2            : 1;        // front center
1426895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexLFE = hasLFE   ? indexFC + 1  : indexFC;  // low frequency
1436895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexBL  = hasBacks ? indexLFE + 1 : indexLFE; // back left
1446895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexBR  = hasBacks ? indexBL + 1  : indexBL;  // back right
1456895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexBC  = hasBC    ? indexBR + 1  : indexBR;  // back center
1466895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexSL  = hasSides ? indexBC + 1  : indexBC;  // side left
1476895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexSR  = hasSides ? indexSL + 1  : indexSL;  // side right
1486895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
1496895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    ALOGI("  FL FR FC LFE BL BR BC SL SR");
1506895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    ALOGI("   %d  %d  %d   %d  %d  %d  %d  %d  %d",
1516895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            0, 1, indexFC, indexLFE, indexBL, indexBR, indexBC, indexSL, indexSR);
1526895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi}
1536895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi#endif
1546895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
1556895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
1566895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi/*----------------------------------------------------------------------------
15704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Effect API implementation
15804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *--------------------------------------------------------------------------*/
15904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
16004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*--- Effect Library Interface Implementation ---*/
16104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
16204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint32_t DownmixLib_QueryNumberEffects(uint32_t *pNumEffects) {
16304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("DownmixLib_QueryNumberEffects()");
16404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    *pNumEffects = kNbEffects;
16504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
16604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
16704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
16804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint32_t DownmixLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
16904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("DownmixLib_QueryEffect() index=%d", index);
17004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (pDescriptor == NULL) {
17104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
17204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
17304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (index >= (uint32_t)kNbEffects) {
17404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
17504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
17604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    memcpy(pDescriptor, gDescriptors[index], sizeof(effect_descriptor_t));
17704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
17804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
17904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
18004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
18104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint32_t DownmixLib_Create(const effect_uuid_t *uuid,
18204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        int32_t sessionId,
18304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        int32_t ioId,
18404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        effect_handle_t *pHandle) {
18504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int ret;
18604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int i;
18704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    downmix_module_t *module;
18804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    const effect_descriptor_t *desc;
18904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
19004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("DownmixLib_Create()");
19104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
1926895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi#ifdef DOWNMIX_TEST_CHANNEL_INDEX
1936895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // should work (won't log an error)
1946895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should work:");
1956895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
1966895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                    AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_BACK_CENTER);
1976895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    Downmix_testIndexComputation(CHANNEL_MASK_QUAD_SIDE | CHANNEL_MASK_QUAD_BACK);
1986895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_SIDE | AUDIO_CHANNEL_OUT_BACK_CENTER);
1996895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    Downmix_testIndexComputation(CHANNEL_MASK_5POINT1_BACK | AUDIO_CHANNEL_OUT_BACK_CENTER);
2006895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // shouldn't work (will log an error, won't display channel indices)
2016895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    ALOGI("DOWNMIX_TEST_CHANNEL_INDEX: should NOT work:");
2026895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
2036895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                        AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_BACK_LEFT);
2046895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT |
2056895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                            AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_SIDE_LEFT);
2066895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT |
2076895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                        AUDIO_CHANNEL_OUT_BACK_LEFT | AUDIO_CHANNEL_OUT_BACK_RIGHT);
2086895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    Downmix_testIndexComputation(AUDIO_CHANNEL_OUT_FRONT_LEFT |
2096895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                            AUDIO_CHANNEL_OUT_SIDE_LEFT | AUDIO_CHANNEL_OUT_SIDE_RIGHT);
2106895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi#endif
2116895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
21204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (pHandle == NULL || uuid == NULL) {
21304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
21404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
21504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
21604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    for (i = 0 ; i < kNbEffects ; i++) {
21704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        desc = gDescriptors[i];
21804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (memcmp(uuid, &desc->uuid, sizeof(effect_uuid_t)) == 0) {
21904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            break;
22004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
22104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
22204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
22304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (i == kNbEffects) {
22404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -ENOENT;
22504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
22604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
22704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    module = malloc(sizeof(downmix_module_t));
22804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
22904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    module->itfe = &gDownmixInterface;
23004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
23104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    module->context.state = DOWNMIX_STATE_UNINITIALIZED;
23204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
23304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ret = Downmix_Init(module);
23404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (ret < 0) {
23504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGW("DownmixLib_Create() init failed");
23604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        free(module);
23704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return ret;
23804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
23904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
24004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    *pHandle = (effect_handle_t) module;
24104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
24204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("DownmixLib_Create() %p , size %d", module, sizeof(downmix_module_t));
24304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
24404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
24504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
24604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
24704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
24804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint32_t DownmixLib_Release(effect_handle_t handle) {
24904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    downmix_module_t *pDwmModule = (downmix_module_t *)handle;
25004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
25104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("DownmixLib_Release() %p", handle);
25204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (handle == NULL) {
25304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
25404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
25504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
25604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->context.state = DOWNMIX_STATE_UNINITIALIZED;
25704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
25804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    free(pDwmModule);
25904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
26004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
26104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
26204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
26304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint32_t DownmixLib_GetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) {
26404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("DownmixLib_GetDescriptor()");
26504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int i;
26604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
26704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (pDescriptor == NULL || uuid == NULL){
26804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGE("DownmixLib_Create() called with NULL pointer");
26904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
27004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
27104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("DownmixLib_GetDescriptor() nb effects=%d", kNbEffects);
27204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    for (i = 0; i < kNbEffects; i++) {
27304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("DownmixLib_GetDescriptor() i=%d", i);
27404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (memcmp(uuid, &gDescriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
27504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            memcpy(pDescriptor, gDescriptors[i], sizeof(effect_descriptor_t));
27604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            ALOGV("EffectGetDescriptor - UUID matched downmix type %d, UUID = %x",
27704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                 i, gDescriptors[i]->uuid.timeLow);
27804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return 0;
27904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
28004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
28104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
28204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return -EINVAL;
28304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
28404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
28504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
28604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*--- Effect Control Interface Implementation ---*/
28704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
28804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivistatic int Downmix_Process(effect_handle_t self,
28904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
29004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
29104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    downmix_object_t *pDownmixer;
29204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int16_t *pSrc, *pDst;
29304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    downmix_module_t *pDwmModule = (downmix_module_t *)self;
29404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
29504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (pDwmModule == NULL) {
29604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
29704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
29804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
29904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (inBuffer == NULL || inBuffer->raw == NULL ||
30004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        outBuffer == NULL || outBuffer->raw == NULL ||
30104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        inBuffer->frameCount != outBuffer->frameCount) {
30204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
30304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
30404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
30504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDownmixer = (downmix_object_t*) &pDwmModule->context;
30604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
30704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (pDownmixer->state == DOWNMIX_STATE_UNINITIALIZED) {
30804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGE("Downmix_Process error: trying to use an uninitialized downmixer");
30904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
31004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    } else if (pDownmixer->state == DOWNMIX_STATE_INITIALIZED) {
31104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGE("Downmix_Process error: trying to use a non-configured downmixer");
31204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -ENODATA;
31304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
31404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
31504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pSrc = inBuffer->s16;
31604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDst = outBuffer->s16;
31704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    size_t numFrames = outBuffer->frameCount;
31804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
31904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    const bool accumulate =
32004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            (pDwmModule->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
3216895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const uint32_t downmixInputChannelMask = pDwmModule->config.inputCfg.channels;
32204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
32304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    switch(pDownmixer->type) {
32404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
32504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      case DOWNMIX_TYPE_STRIP:
32604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi          if (accumulate) {
32704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi              while (numFrames) {
32804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  pDst[0] = clamp16(pDst[0] + pSrc[0]);
32904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  pDst[1] = clamp16(pDst[1] + pSrc[1]);
33004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  pSrc += pDownmixer->input_channel_count;
33104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  pDst += 2;
33204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  numFrames--;
33304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi              }
33404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi          } else {
33504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi              while (numFrames) {
33604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  pDst[0] = pSrc[0];
33704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  pDst[1] = pSrc[1];
33804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  pSrc += pDownmixer->input_channel_count;
33904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  pDst += 2;
34004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                  numFrames--;
34104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi              }
34204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi          }
34304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi          break;
34404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
34504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      case DOWNMIX_TYPE_FOLD:
3466895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi#ifdef DOWNMIX_ALWAYS_USE_GENERIC_DOWNMIXER
3476895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi          // bypass the optimized downmix routines for the common formats
3486895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi          if (!Downmix_foldGeneric(
3496895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                  downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
3506895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi              ALOGE("Multichannel configuration 0x%x is not supported", downmixInputChannelMask);
3516895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi              return -EINVAL;
3526895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi          }
3536895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi          break;
3546895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi#endif
35504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        // optimize for the common formats
3566895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        switch((downmix_input_channel_mask_t)downmixInputChannelMask) {
357db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi        case CHANNEL_MASK_QUAD_BACK:
358db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi        case CHANNEL_MASK_QUAD_SIDE:
35904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            Downmix_foldFromQuad(pSrc, pDst, numFrames, accumulate);
36004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            break;
361db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi        case CHANNEL_MASK_SURROUND:
36204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            Downmix_foldFromSurround(pSrc, pDst, numFrames, accumulate);
36304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            break;
364db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi        case CHANNEL_MASK_5POINT1_BACK:
365db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi        case CHANNEL_MASK_5POINT1_SIDE:
36604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            Downmix_foldFrom5Point1(pSrc, pDst, numFrames, accumulate);
36704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            break;
368db46b48d24e03f5bcb8de6d0ff852ec4153401e7Jean-Michel Trivi        case CHANNEL_MASK_7POINT1_SIDE_BACK:
36904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            Downmix_foldFrom7Point1(pSrc, pDst, numFrames, accumulate);
37004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            break;
37104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        default:
3726895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (!Downmix_foldGeneric(
3736895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                    downmixInputChannelMask, pSrc, pDst, numFrames, accumulate)) {
3746895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                ALOGE("Multichannel configuration 0x%x is not supported", downmixInputChannelMask);
3756895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                return -EINVAL;
3766895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            }
37704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            break;
37804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
37904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
38004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
38104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      default:
38204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
38304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
38404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
38504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
38604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
38704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
38804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
38904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivistatic int Downmix_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
39004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        void *pCmdData, uint32_t *replySize, void *pReplyData) {
39104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
39204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    downmix_module_t *pDwmModule = (downmix_module_t *) self;
39304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    downmix_object_t *pDownmixer;
39404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int retsize;
39504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
39604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (pDwmModule == NULL || pDwmModule->context.state == DOWNMIX_STATE_UNINITIALIZED) {
39704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
39804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
39904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
40004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDownmixer = (downmix_object_t*) &pDwmModule->context;
40104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
40204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("Downmix_Command command %d cmdSize %d",cmdCode, cmdSize);
40304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
40404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    switch (cmdCode) {
40504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_INIT:
40604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pReplyData == NULL || *replySize != sizeof(int)) {
40704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
40804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
40904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        *(int *) pReplyData = Downmix_Init(pDwmModule);
41004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
41104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
41204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_CONFIG:
41304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
41404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                || pReplyData == NULL || *replySize != sizeof(int)) {
41504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
41604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
41704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        *(int *) pReplyData = Downmix_Configure(pDwmModule,
41804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                (effect_config_t *)pCmdData, false);
41904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
42004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
42104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_RESET:
42204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        Downmix_Reset(pDownmixer, false);
42304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
42404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
42504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_GET_PARAM:
42604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %d, pReplyData: %p",
42704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                pCmdData, *replySize, pReplyData);
42804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
42904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                pReplyData == NULL ||
43004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                *replySize < (int) sizeof(effect_param_t) + 2 * sizeof(int32_t)) {
43104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
43204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
43304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        effect_param_t *rep = (effect_param_t *) pReplyData;
43404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(int32_t));
43504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM param %d, replySize %d",
43604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                *(int32_t *)rep->data, rep->vsize);
43704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        rep->status = Downmix_getParameter(pDownmixer, *(int32_t *)rep->data, &rep->vsize,
43804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                rep->data + sizeof(int32_t));
43904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        *replySize = sizeof(effect_param_t) + sizeof(int32_t) + rep->vsize;
44004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
44104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
44204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_PARAM:
44304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, " \
44404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                "pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
44504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
44604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                || pReplyData == NULL || *replySize != (int)sizeof(int32_t)) {
44704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
44804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
44904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        effect_param_t *cmd = (effect_param_t *) pCmdData;
45004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        *(int *)pReplyData = Downmix_setParameter(pDownmixer, *(int32_t *)cmd->data,
45104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                cmd->vsize, cmd->data + sizeof(int32_t));
45204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
45304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
45404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_PARAM_DEFERRED:
45504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        //FIXME implement
45604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGW("Downmix_Command command EFFECT_CMD_SET_PARAM_DEFERRED not supported, FIXME");
45704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
45804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
45904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_PARAM_COMMIT:
46004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        //FIXME implement
46104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGW("Downmix_Command command EFFECT_CMD_SET_PARAM_COMMIT not supported, FIXME");
46204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
46304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
46404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_ENABLE:
46504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pReplyData == NULL || *replySize != sizeof(int)) {
46604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
46704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
46804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pDownmixer->state != DOWNMIX_STATE_INITIALIZED) {
46904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -ENOSYS;
47004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
47104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        pDownmixer->state = DOWNMIX_STATE_ACTIVE;
47204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("EFFECT_CMD_ENABLE() OK");
47304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        *(int *)pReplyData = 0;
47404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
47504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
47604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_DISABLE:
47704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pReplyData == NULL || *replySize != sizeof(int)) {
47804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
47904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
48004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pDownmixer->state != DOWNMIX_STATE_ACTIVE) {
48104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -ENOSYS;
48204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
48304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        pDownmixer->state = DOWNMIX_STATE_INITIALIZED;
48404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("EFFECT_CMD_DISABLE() OK");
48504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        *(int *)pReplyData = 0;
48604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
48704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
48804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_DEVICE:
48904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
49004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
49104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
49204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        // FIXME change type if playing on headset vs speaker
49304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("Downmix_Command EFFECT_CMD_SET_DEVICE: 0x%08x", *(uint32_t *)pCmdData);
49404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
49504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
49604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_VOLUME: {
49704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        // audio output is always stereo => 2 channel volumes
49804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t) * 2) {
49904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
50004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
50104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        // FIXME change volume
50204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGW("Downmix_Command command EFFECT_CMD_SET_VOLUME not supported, FIXME");
50304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        float left = (float)(*(uint32_t *)pCmdData) / (1 << 24);
50404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        float right = (float)(*((uint32_t *)pCmdData + 1)) / (1 << 24);
50504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("Downmix_Command EFFECT_CMD_SET_VOLUME: left %f, right %f ", left, right);
50604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
50704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
50804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
50904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_AUDIO_MODE:
51004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
51104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
51204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
51304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("Downmix_Command EFFECT_CMD_SET_AUDIO_MODE: %d", *(uint32_t *)pCmdData);
51404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
51504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
51604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_CONFIG_REVERSE:
51704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case EFFECT_CMD_SET_INPUT_DEVICE:
51804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        // these commands are ignored by a downmix effect
51904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
52004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
52104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    default:
52204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGW("Downmix_Command invalid command %d",cmdCode);
52304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
52404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
52504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
52604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
52704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
52804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
52904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
53004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint Downmix_GetDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor)
53104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi{
53204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    downmix_module_t *pDwnmxModule = (downmix_module_t *) self;
53304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
53404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (pDwnmxModule == NULL ||
53504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDwnmxModule->context.state == DOWNMIX_STATE_UNINITIALIZED) {
53604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
53704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
53804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
53904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    memcpy(pDescriptor, &gDownmixDescriptor, sizeof(effect_descriptor_t));
54004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
54104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
54204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
54304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
54404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
54504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
54604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix internal functions
54704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *--------------------------------------------------------------------------*/
54804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
54904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
55004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_Init()
55104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
55204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
55304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Initialize downmix context and apply default parameters
55404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
55504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
55604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDwmModule    pointer to downmix effect module
55704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
55804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
55904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
56004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Returns:
56104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  0             indicates success
56204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
56304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Side Effects:
56404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  updates:
56504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *           pDwmModule->context.type
56604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *           pDwmModule->context.apply_volume_correction
56704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *           pDwmModule->config.inputCfg
56804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *           pDwmModule->config.outputCfg
56904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *           pDwmModule->config.inputCfg.samplingRate
57004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *           pDwmModule->config.outputCfg.samplingRate
57104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *           pDwmModule->context.state
57204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  doesn't set:
57304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *           pDwmModule->itfe
57404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
57504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
57604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
57704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
57804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint Downmix_Init(downmix_module_t *pDwmModule) {
57904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
58004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("Downmix_Init module %p", pDwmModule);
58104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int ret = 0;
58204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
58304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    memset(&pDwmModule->context, 0, sizeof(downmix_object_t));
58404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
58504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
58604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
58704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1;
58804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.inputCfg.bufferProvider.getBuffer = NULL;
58904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.inputCfg.bufferProvider.releaseBuffer = NULL;
59004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.inputCfg.bufferProvider.cookie = NULL;
59104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.inputCfg.mask = EFFECT_CONFIG_ALL;
59204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
59304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.inputCfg.samplingRate = 44100;
59404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.outputCfg.samplingRate = pDwmModule->config.inputCfg.samplingRate;
59504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
59604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // set a default value for the access mode, but should be overwritten by caller
59704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
59804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
59904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
60004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.outputCfg.bufferProvider.getBuffer = NULL;
60104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.outputCfg.bufferProvider.releaseBuffer = NULL;
60204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.outputCfg.bufferProvider.cookie = NULL;
60304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    pDwmModule->config.outputCfg.mask = EFFECT_CONFIG_ALL;
60404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
60504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ret = Downmix_Configure(pDwmModule, &pDwmModule->config, true);
60604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (ret != 0) {
60704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("Downmix_Init error %d on module %p", ret, pDwmModule);
60804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    } else {
60904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        pDwmModule->context.state = DOWNMIX_STATE_INITIALIZED;
61004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
61104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
61204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return ret;
61304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
61404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
61504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
61604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
61704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_Configure()
61804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
61904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
62004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  Set input and output audio configuration.
62104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
62204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
62304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDwmModule  pointer to downmix effect module
62404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pConfig     pointer to effect_config_t structure containing input
62504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *                  and output audio parameters configuration
62604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  init        true if called from init function
62704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
62804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
62904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
63004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Returns:
63104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  0           indicates success
63204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
63304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Side Effects:
63404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
63504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
63604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
63704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
63804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bool init) {
63904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
64004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    downmix_object_t *pDownmixer = &pDwmModule->context;
64104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
64204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // Check configuration compatibility with build options, and effect capabilities
64304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate
64404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        || pConfig->outputCfg.channels != DOWNMIX_OUTPUT_CHANNELS
64504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        || pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT
64604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        || pConfig->outputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
64704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGE("Downmix_Configure error: invalid config");
64804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
64904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
65004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
65104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    memcpy(&pDwmModule->config, pConfig, sizeof(effect_config_t));
65204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
65304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (init) {
65404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        pDownmixer->type = DOWNMIX_TYPE_FOLD;
65504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        pDownmixer->apply_volume_correction = false;
65604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        pDownmixer->input_channel_count = 8; // matches default input of AUDIO_CHANNEL_OUT_7POINT1
65704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    } else {
65804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        // when configuring the effect, do not allow a blank channel mask
65904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (pConfig->inputCfg.channels == 0) {
66004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            ALOGE("Downmix_Configure error: input channel mask can't be 0");
66104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
66204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
66304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        pDownmixer->input_channel_count = popcount(pConfig->inputCfg.channels);
66404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
66504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
66604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    Downmix_Reset(pDownmixer, init);
66704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
66804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
66904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
67004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
67104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
67204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
67304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_Reset()
67404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
67504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
67604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  Reset internal states.
67704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
67804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
67904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDownmixer   pointer to downmix context
68004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  init         true if called from init function
68104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
68204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
68304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi*
68404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Returns:
68504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  0            indicates success
68604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
68704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Side Effects:
68804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
68904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
69004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
69104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
69204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint Downmix_Reset(downmix_object_t *pDownmixer, bool init) {
69304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // nothing to do here
69404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
69504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
69604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
69704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
69804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
69904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_setParameter()
70004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
70104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
70204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Set a Downmix parameter
70304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
70404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
70504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDownmixer    handle to instance data
70604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  param         parameter
70704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pValue        pointer to parameter value
70804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  size          value size
70904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
71004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
71104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
71204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Returns:
71304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  0             indicates success
71404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
71504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Side Effects:
71604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
71704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
71804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
71904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint Downmix_setParameter(downmix_object_t *pDownmixer, int32_t param, size_t size, void *pValue) {
72004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
72104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int16_t value16;
72204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    ALOGV("Downmix_setParameter, context %p, param %d, value16 %d, value32 %d",
72304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDownmixer, param, *(int16_t *)pValue, *(int32_t *)pValue);
72404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
72504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    switch (param) {
72604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
72704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      case DOWNMIX_PARAM_TYPE:
72804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        if (size != sizeof(downmix_type_t)) {
72904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            ALOGE("Downmix_setParameter(DOWNMIX_PARAM_TYPE) invalid size %d, should be %d",
73004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                    size, sizeof(downmix_type_t));
73104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
73204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
73304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        value16 = *(int16_t *)pValue;
73404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGV("set DOWNMIX_PARAM_TYPE, type %d", value16);
7357d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi        if (!((value16 > DOWNMIX_TYPE_INVALID) && (value16 <= DOWNMIX_TYPE_LAST))) {
73604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            ALOGE("Downmix_setParameter invalid DOWNMIX_PARAM_TYPE value %d", value16);
73704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            return -EINVAL;
73804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        } else {
73904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDownmixer->type = (downmix_type_t) value16;
74004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        break;
74104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
74204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      default:
74304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        ALOGE("Downmix_setParameter unknown parameter %d", param);
74404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        return -EINVAL;
74504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
74604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
74704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
74804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
74904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi} /* end Downmix_setParameter */
75004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
75104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
75204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
75304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_getParameter()
75404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
75504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
75604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Get a Downmix parameter
75704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
75804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
75904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDownmixer    handle to instance data
76004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  param         parameter
76104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pValue        pointer to variable to hold retrieved value
76204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pSize         pointer to value size: maximum size as input
76304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
76404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
76504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  *pValue updated with parameter value
76604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  *pSize updated with actual value size
76704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
76804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Returns:
76904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  0             indicates success
77004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
77104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Side Effects:
77204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
77304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
77404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
77504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Triviint Downmix_getParameter(downmix_object_t *pDownmixer, int32_t param, size_t *pSize, void *pValue) {
77604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int16_t *pValue16;
77704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
77804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    switch (param) {
77904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
78004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    case DOWNMIX_PARAM_TYPE:
78104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      if (*pSize < sizeof(int16_t)) {
78204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi          ALOGE("Downmix_getParameter invalid parameter size %d for DOWNMIX_PARAM_TYPE", *pSize);
78304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi          return -EINVAL;
78404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      }
78504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      pValue16 = (int16_t *)pValue;
78604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      *pValue16 = (int16_t) pDownmixer->type;
78704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      *pSize = sizeof(int16_t);
78804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      ALOGV("Downmix_getParameter DOWNMIX_PARAM_TYPE is %d", *pValue16);
78904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      break;
79004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
79104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    default:
79204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      ALOGE("Downmix_getParameter unknown parameter %d", param);
79304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi      return -EINVAL;
79404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
79504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
79604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    return 0;
79704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi} /* end Downmix_getParameter */
79804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
79904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
80004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
80104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_foldFromQuad()
80204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
80304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
80404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * downmix a quad signal to stereo
80504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
80604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
80704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pSrc       quad audio samples to downmix
80804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  numFrames  the number of quad frames to downmix
8096895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
8106895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *               or overwrite pDst (when false)
81104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
81204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
81304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDst       downmixed stereo audio samples
81404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
81504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
81604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
81704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivivoid Downmix_foldFromQuad(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
81804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 0 is FL
81904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 1 is FR
82004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 2 is RL
82104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 3 is RR
82204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (accumulate) {
82304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        while (numFrames) {
82404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FL + RL
825aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(pDst[0] + ((pSrc[0] + pSrc[2]) >> 1));
82604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FR + RR
827aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(pDst[1] + ((pSrc[1] + pSrc[3]) >> 1));
82804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pSrc += 4;
82904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDst += 2;
83004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            numFrames--;
83104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
83204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    } else { // same code as above but without adding and clamping pDst[i] to itself
83304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        while (numFrames) {
83404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FL + RL
835aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16((pSrc[0] + pSrc[2]) >> 1);
83604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FR + RR
837aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16((pSrc[1] + pSrc[3]) >> 1);
83804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pSrc += 4;
83904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDst += 2;
84004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            numFrames--;
84104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
84204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
84304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
84404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
84504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
84604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
84704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_foldFromSurround()
84804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
84904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
85004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * downmix a "surround sound" (mono rear) signal to stereo
85104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
85204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
85304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pSrc       surround signal to downmix
85404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  numFrames  the number of surround frames to downmix
8556895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
8566895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *               or overwrite pDst (when false)
85704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
85804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
85904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDst       downmixed stereo audio samples
86004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
86104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
86204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
86304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivivoid Downmix_foldFromSurround(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
86404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int32_t lt, rt, centerPlusRearContrib; // samples in Q19.12 format
86504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 0 is FL
86604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 1 is FR
86704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 2 is FC
86804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 3 is RC
8696895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // code is mostly duplicated between the two values of accumulate to avoid repeating the test
8706895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // for every sample
87104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (accumulate) {
87204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        while (numFrames) {
87304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // centerPlusRearContrib = FC(-3dB) + RC(-3dB)
87404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            centerPlusRearContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12) + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
87504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FL + centerPlusRearContrib
87604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            lt = (pSrc[0] << 12) + centerPlusRearContrib;
87704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FR + centerPlusRearContrib
87804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            rt = (pSrc[1] << 12) + centerPlusRearContrib;
8796895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // accumulate in destination
880aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(pDst[0] + (lt >> 13));
881aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(pDst[1] + (rt >> 13));
88204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pSrc += 4;
88304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDst += 2;
88404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            numFrames--;
88504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
88604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    } else { // same code as above but without adding and clamping pDst[i] to itself
88704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        while (numFrames) {
88804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // centerPlusRearContrib = FC(-3dB) + RC(-3dB)
88904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            centerPlusRearContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12) + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
89004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FL + centerPlusRearContrib
89104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            lt = (pSrc[0] << 12) + centerPlusRearContrib;
89204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FR + centerPlusRearContrib
89304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            rt = (pSrc[1] << 12) + centerPlusRearContrib;
8946895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // store in destination
895aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above
896aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above
89704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pSrc += 4;
89804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDst += 2;
89904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            numFrames--;
90004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
90104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
90204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
90304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
90404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
90504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
90604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_foldFrom5Point1()
90704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
90804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
90904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * downmix a 5.1 signal to stereo
91004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
91104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
91204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pSrc       5.1 audio samples to downmix
91304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  numFrames  the number of 5.1 frames to downmix
9146895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
9156895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *               or overwrite pDst (when false)
91604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
91704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
91804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDst       downmixed stereo audio samples
91904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
92004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
92104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
92204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivivoid Downmix_foldFrom5Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
92304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
92404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 0 is FL
92504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 1 is FR
92604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 2 is FC
92704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 3 is LFE
92804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 4 is RL
92904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 5 is RR
9306895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // code is mostly duplicated between the two values of accumulate to avoid repeating the test
9316895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // for every sample
93204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (accumulate) {
93304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        while (numFrames) {
93404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
93504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
93604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                    + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
93704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FL + centerPlusLfeContrib + RL
93804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[4] << 12);
93904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FR + centerPlusLfeContrib + RR
94004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[5] << 12);
9416895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // accumulate in destination
942aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(pDst[0] + (lt >> 13));
943aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(pDst[1] + (rt >> 13));
94404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pSrc += 6;
94504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDst += 2;
94604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            numFrames--;
94704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
94804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    } else { // same code as above but without adding and clamping pDst[i] to itself
94904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        while (numFrames) {
95004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
95104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
95204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                    + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
95304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FL + centerPlusLfeContrib + RL
95404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[4] << 12);
95504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FR + centerPlusLfeContrib + RR
95604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[5] << 12);
9576895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // store in destination
958aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above
959aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above
96004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pSrc += 6;
96104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDst += 2;
96204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            numFrames--;
96304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
96404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
96504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
96604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
96704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
96804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi/*----------------------------------------------------------------------------
96904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Downmix_foldFrom7Point1()
97004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
97104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Purpose:
97204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * downmix a 7.1 signal to stereo
97304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
97404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Inputs:
97504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pSrc       7.1 audio samples to downmix
97604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  numFrames  the number of 7.1 frames to downmix
9776895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
9786895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *               or overwrite pDst (when false)
97904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
98004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi * Outputs:
98104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *  pDst       downmixed stereo audio samples
98204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *
98304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi *----------------------------------------------------------------------------
98404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi */
98504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivivoid Downmix_foldFrom7Point1(int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
98604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    int32_t lt, rt, centerPlusLfeContrib; // samples in Q19.12 format
98704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 0 is FL
98804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 1 is FR
98904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 2 is FC
99004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 3 is LFE
99104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 4 is RL
99204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 5 is RR
99304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 6 is SL
99404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    // sample at index 7 is SR
9956895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // code is mostly duplicated between the two values of accumulate to avoid repeating the test
9966895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // for every sample
99704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    if (accumulate) {
99804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        while (numFrames) {
99904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
100004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
100104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                    + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
100204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FL + centerPlusLfeContrib + SL + RL
100304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[6] << 12) + (pSrc[4] << 12);
100404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FR + centerPlusLfeContrib + SR + RR
100504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[7] << 12) + (pSrc[5] << 12);
10066895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            //accumulate in destination
1007aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(pDst[0] + (lt >> 13));
1008aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(pDst[1] + (rt >> 13));
100904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pSrc += 8;
101004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDst += 2;
101104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            numFrames--;
101204c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
101304c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    } else { // same code as above but without adding and clamping pDst[i] to itself
101404c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        while (numFrames) {
101504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // centerPlusLfeContrib = FC(-3dB) + LFE(-3dB)
101604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            centerPlusLfeContrib = (pSrc[2] * MINUS_3_DB_IN_Q19_12)
101704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi                    + (pSrc[3] * MINUS_3_DB_IN_Q19_12);
101804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FL + centerPlusLfeContrib + SL + RL
101904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            lt = (pSrc[0] << 12) + centerPlusLfeContrib + (pSrc[6] << 12) + (pSrc[4] << 12);
102004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            // FR + centerPlusLfeContrib + SR + RR
102104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            rt = (pSrc[1] << 12) + centerPlusLfeContrib + (pSrc[7] << 12) + (pSrc[5] << 12);
10226895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // store in destination
1023aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above
1024aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above
102504c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pSrc += 8;
102604c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            pDst += 2;
102704c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi            numFrames--;
102804c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi        }
102904c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi    }
103004c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi}
103104c1e531b5913c09aa9b2e59e2b8ed9b4d8a4cbaJean-Michel Trivi
10326895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
10336895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi/*----------------------------------------------------------------------------
10346895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi * Downmix_foldGeneric()
10356895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *----------------------------------------------------------------------------
10366895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi * Purpose:
10376895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi * downmix to stereo a multichannel signal whose format is:
10386895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  - has FL/FR
10396895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  - if using AUDIO_CHANNEL_OUT_SIDE*, it contains both left and right
10406895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  - if using AUDIO_CHANNEL_OUT_BACK*, it contains both left and right
10416895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  - doesn't use any of the AUDIO_CHANNEL_OUT_TOP* channels
10426895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  - doesn't use any of the AUDIO_CHANNEL_OUT_FRONT_*_OF_CENTER channels
10436895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi * Only handles channel masks not enumerated in downmix_input_channel_mask_t
10446895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *
10456895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi * Inputs:
10466895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  mask       the channel mask of pSrc
10476895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  pSrc       multichannel audio buffer to downmix
10486895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  numFrames  the number of multichannel frames to downmix
10496895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  accumulate whether to mix (when true) the result of the downmix with the contents of pDst,
10506895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *               or overwrite pDst (when false)
10516895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *
10526895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi * Outputs:
10536895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *  pDst       downmixed stereo audio samples
10546895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *
10556895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi * Returns: false if multichannel format is not supported
10566895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *
10576895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi *----------------------------------------------------------------------------
10586895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi */
10596895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivibool Downmix_foldGeneric(
10606895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        uint32_t mask, int16_t *pSrc, int16_t*pDst, size_t numFrames, bool accumulate) {
10616895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // check against unsupported channels
10626895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if (mask & kUnsupported) {
10636895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        ALOGE("Unsupported channels (top or front left/right of center)");
10646895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        return false;
10656895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
10666895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // verify has FL/FR
10676895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if ((mask & AUDIO_CHANNEL_OUT_STEREO) != AUDIO_CHANNEL_OUT_STEREO) {
10686895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        ALOGE("Front channels must be present");
10696895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        return false;
10706895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
10716895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // verify uses SIDE as a pair (ok if not using SIDE at all)
10726895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    bool hasSides = false;
10736895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if ((mask & kSides) != 0) {
10746895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        if ((mask & kSides) != kSides) {
10756895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            ALOGE("Side channels must be used as a pair");
10766895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            return false;
10776895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        }
10786895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        hasSides = true;
10796895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
10806895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // verify uses BACK as a pair (ok if not using BACK at all)
10816895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    bool hasBacks = false;
10826895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if ((mask & kBacks) != 0) {
10836895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        if ((mask & kBacks) != kBacks) {
10846895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            ALOGE("Back channels must be used as a pair");
10856895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            return false;
10866895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        }
10876895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        hasBacks = true;
10886895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
10896895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
10906895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int numChan = popcount(mask);
10916895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const bool hasFC = ((mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) == AUDIO_CHANNEL_OUT_FRONT_CENTER);
10926895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const bool hasLFE =
10936895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            ((mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) == AUDIO_CHANNEL_OUT_LOW_FREQUENCY);
10946895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const bool hasBC = ((mask & AUDIO_CHANNEL_OUT_BACK_CENTER) == AUDIO_CHANNEL_OUT_BACK_CENTER);
10956895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // compute at what index each channel is: samples will be in the following order:
10966895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    //   FL FR FC LFE BL BR BC SL SR
10976895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // when a channel is not present, its index is set to the same as the index of the preceding
10986895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // channel
10996895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexFC  = hasFC    ? 2            : 1;        // front center
11006895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexLFE = hasLFE   ? indexFC + 1  : indexFC;  // low frequency
11016895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexBL  = hasBacks ? indexLFE + 1 : indexLFE; // back left
11026895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexBR  = hasBacks ? indexBL + 1  : indexBL;  // back right
11036895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexBC  = hasBC    ? indexBR + 1  : indexBR;  // back center
11046895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexSL  = hasSides ? indexBC + 1  : indexBC;  // side left
11056895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    const int indexSR  = hasSides ? indexSL + 1  : indexSL;  // side right
11066895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi
11076895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    int32_t lt, rt, centersLfeContrib; // samples in Q19.12 format
11086895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // code is mostly duplicated between the two values of accumulate to avoid repeating the test
11096895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    // for every sample
11106895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    if (accumulate) {
11116895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        while (numFrames) {
11126895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // compute contribution of FC, BC and LFE
11136895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            centersLfeContrib = 0;
11146895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasFC)  { centersLfeContrib += pSrc[indexFC]; }
11156895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
11166895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasBC)  { centersLfeContrib += pSrc[indexBC]; }
11176895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            centersLfeContrib *= MINUS_3_DB_IN_Q19_12;
11186895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // always has FL/FR
11196895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            lt = (pSrc[0] << 12);
11206895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            rt = (pSrc[1] << 12);
11216895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // mix in sides and backs
11226895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasSides) {
11236895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                lt += pSrc[indexSL] << 12;
11246895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                rt += pSrc[indexSR] << 12;
11256895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            }
11266895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasBacks) {
11276895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                lt += pSrc[indexBL] << 12;
11286895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                rt += pSrc[indexBR] << 12;
11296895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            }
11306895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            lt += centersLfeContrib;
11316895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            rt += centersLfeContrib;
11326895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // accumulate in destination
1133aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(pDst[0] + (lt >> 13));
1134aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(pDst[1] + (rt >> 13));
11356895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            pSrc += numChan;
11366895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            pDst += 2;
11376895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            numFrames--;
11386895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        }
11396895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    } else {
11406895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        while (numFrames) {
11416895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // compute contribution of FC, BC and LFE
11426895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            centersLfeContrib = 0;
11436895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasFC)  { centersLfeContrib += pSrc[indexFC]; }
11446895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasLFE) { centersLfeContrib += pSrc[indexLFE]; }
11456895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasBC)  { centersLfeContrib += pSrc[indexBC]; }
11466895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            centersLfeContrib *= MINUS_3_DB_IN_Q19_12;
11476895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // always has FL/FR
11486895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            lt = (pSrc[0] << 12);
11496895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            rt = (pSrc[1] << 12);
11506895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // mix in sides and backs
11516895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasSides) {
11526895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                lt += pSrc[indexSL] << 12;
11536895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                rt += pSrc[indexSR] << 12;
11546895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            }
11556895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            if (hasBacks) {
11566895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                lt += pSrc[indexBL] << 12;
11576895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi                rt += pSrc[indexBR] << 12;
11586895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            }
11596895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            lt += centersLfeContrib;
11606895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            rt += centersLfeContrib;
11616895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            // store in destination
1162aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[0] = clamp16(lt >> 13); // differs from when accumulate is true above
1163aea2715e65994e665a3732551880419ba1cecc0dJean-Michel Trivi            pDst[1] = clamp16(rt >> 13); // differs from when accumulate is true above
11646895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            pSrc += numChan;
11656895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            pDst += 2;
11666895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi            numFrames--;
11676895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi        }
11686895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    }
11696895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi    return true;
11706895deeecc8797e6f5b28e7d07ec6bc499355c0cJean-Michel Trivi}
1171