1178 lines
29 KiB
C
1178 lines
29 KiB
C
/*
|
|
* Copyright (C) 2018 Amlogic Corporation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* DESCRIPTION:
|
|
* This program is the factory of PCM data.
|
|
*
|
|
*/
|
|
|
|
#define LOG_TAG "audio_data_utils"
|
|
//#define LOG_NDEBUG 0
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include "aml_audio_log.h"
|
|
#include <fcntl.h>
|
|
#include <math.h>
|
|
#include <aml_data_utils.h>
|
|
#include <aml_audio_hal_conf.h>
|
|
#include <aml_conf_parser.h>
|
|
#include <aml_conf_loader.h>
|
|
#include "aml_malloc_debug.h"
|
|
|
|
#if defined (BUILDHOSTEXE)
|
|
//#define DEBUG
|
|
#ifdef DEBUG
|
|
#define AMLOGE printf
|
|
#define AMLOGD printf
|
|
#else
|
|
#define AMLOGE
|
|
#define AMLOGD
|
|
#endif
|
|
#else
|
|
#define AMLOGE ALOGE
|
|
#define AMLOGD ALOGD
|
|
#endif
|
|
|
|
static struct aml_audio_channel_name gAudioChName[] = {
|
|
{AML_CH_IDX_L, "left"},
|
|
{AML_CH_IDX_R, "right"},
|
|
{AML_CH_IDX_C, "center"},
|
|
{AML_CH_IDX_LFE, "lfe"},
|
|
{AML_CH_IDX_LS, "left_surround"},
|
|
{AML_CH_IDX_RS, "right_urround"},
|
|
{AML_CH_IDX_LT, "left_top"},
|
|
{AML_CH_IDX_RT, "right_top"},
|
|
};
|
|
|
|
static int _name_trans_to_i2s_chidx(const char *name)
|
|
{
|
|
if (!strcmp(name, gAudioChName[0].ch_name)) {
|
|
return gAudioChName[0].ch_idx;
|
|
} else if (!strcmp(name, gAudioChName[1].ch_name)) {
|
|
return gAudioChName[1].ch_idx;
|
|
} else if (!strcmp(name, gAudioChName[2].ch_name)) {
|
|
return gAudioChName[2].ch_idx;
|
|
} else if (!strcmp(name, gAudioChName[3].ch_name)) {
|
|
return gAudioChName[3].ch_idx;
|
|
} else if (!strcmp(name, gAudioChName[4].ch_name)) {
|
|
return gAudioChName[4].ch_idx;
|
|
} else if (!strcmp(name, gAudioChName[5].ch_name)) {
|
|
return gAudioChName[5].ch_idx;
|
|
} else if (!strcmp(name, gAudioChName[6].ch_name)) {
|
|
return gAudioChName[6].ch_idx;
|
|
} else if (!strcmp(name, gAudioChName[7].ch_name)) {
|
|
return gAudioChName[7].ch_idx;
|
|
}
|
|
return AML_CH_IDX_NULL;
|
|
}
|
|
|
|
static inline int16_t _clamp16(int32_t sample)
|
|
{
|
|
if ((sample>>15) ^ (sample>>31))
|
|
sample = 0x7FFF ^ (sample>>31);
|
|
return sample;
|
|
}
|
|
|
|
/*
|
|
static inline int32_t _clamp32(int64_t sample)
|
|
{
|
|
//TODO:
|
|
return sample;
|
|
}
|
|
*/
|
|
|
|
static char *_get_ch_name(eChannelContentIdx idx)
|
|
{
|
|
int i = 0;
|
|
int cnt = 0;
|
|
|
|
cnt = sizeof(gAudioChName)/sizeof(struct aml_audio_channel_name);
|
|
|
|
for (i=AML_CH_IDX_L; i<AML_I2S_CHANNEL_COUNT; i++) {
|
|
if (idx == gAudioChName[i].ch_idx) {
|
|
return gAudioChName[i].ch_name;
|
|
}
|
|
}
|
|
|
|
switch (idx) {
|
|
case AML_CH_IDX_5_1_ALL:
|
|
return "5.1Ch";
|
|
case AML_CH_IDX_7_1_ALL:
|
|
return "7.1Ch";
|
|
case AML_CH_IDX_5_1_2_ALL:
|
|
return "5.1.2Ch";
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return "Invalid";
|
|
}
|
|
|
|
#define SHENPENGRU_TEST (0)
|
|
|
|
#if SHENPENGRU_TEST
|
|
struct aml_channel_map test_maps[] = {
|
|
{AML_CH_IDX_L, AML_I2S_PORT_IDX_01, AML_I2S_CHANNEL_0},
|
|
{AML_CH_IDX_R, AML_I2S_PORT_IDX_01, AML_I2S_CHANNEL_1},
|
|
{AML_CH_IDX_C, AML_I2S_PORT_IDX_23, AML_I2S_CHANNEL_2},
|
|
{AML_CH_IDX_LFE, AML_I2S_PORT_IDX_23, AML_I2S_CHANNEL_3},
|
|
{AML_CH_IDX_LS, AML_I2S_PORT_IDX_67, AML_I2S_CHANNEL_6},
|
|
{AML_CH_IDX_RS, AML_I2S_PORT_IDX_67, AML_I2S_CHANNEL_7},
|
|
{AML_CH_IDX_LT, AML_I2S_PORT_IDX_45, AML_I2S_CHANNEL_4},
|
|
{AML_CH_IDX_RT, AML_I2S_PORT_IDX_45, AML_I2S_CHANNEL_5},
|
|
};
|
|
#endif
|
|
|
|
static char *_get_ch_conf_name(int type, int content_idx)
|
|
{
|
|
switch (type) {
|
|
case eAmlConfTypeChMap:
|
|
switch (content_idx) {
|
|
case AML_CH_IDX_L:
|
|
return AML_I2S_CHANNEL0;
|
|
case AML_CH_IDX_R:
|
|
return AML_I2S_CHANNEL1;
|
|
case AML_CH_IDX_C:
|
|
return AML_I2S_CHANNEL2;
|
|
case AML_CH_IDX_LFE:
|
|
return AML_I2S_CHANNEL3;
|
|
case AML_CH_IDX_LS:
|
|
return AML_I2S_CHANNEL4;
|
|
case AML_CH_IDX_RS:
|
|
return AML_I2S_CHANNEL5;
|
|
case AML_CH_IDX_LT:
|
|
return AML_I2S_CHANNEL6;
|
|
case AML_CH_IDX_RT:
|
|
return AML_I2S_CHANNEL7;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case eAmlConfTypeChInv:
|
|
switch (content_idx) {
|
|
case AML_CH_IDX_L:
|
|
return AML_I2S_INVERT_CH0;
|
|
case AML_CH_IDX_R:
|
|
return AML_I2S_INVERT_CH1;
|
|
case AML_CH_IDX_C:
|
|
return AML_I2S_INVERT_CH2;
|
|
case AML_CH_IDX_LFE:
|
|
return AML_I2S_INVERT_CH3;
|
|
case AML_CH_IDX_LS:
|
|
return AML_I2S_INVERT_CH4;
|
|
case AML_CH_IDX_RS:
|
|
return AML_I2S_INVERT_CH5;
|
|
case AML_CH_IDX_LT:
|
|
return AML_I2S_INVERT_CH6;
|
|
case AML_CH_IDX_RT:
|
|
return AML_I2S_INVERT_CH7;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case eAmlConfTypeChDit:
|
|
switch (content_idx) {
|
|
case AML_CH_IDX_L:
|
|
return AML_DITTER_I2S_CH0;
|
|
case AML_CH_IDX_R:
|
|
return AML_DITTER_I2S_CH1;
|
|
case AML_CH_IDX_C:
|
|
return AML_DITTER_I2S_CH2;
|
|
case AML_CH_IDX_LFE:
|
|
return AML_DITTER_I2S_CH3;
|
|
case AML_CH_IDX_LS:
|
|
return AML_DITTER_I2S_CH4;
|
|
case AML_CH_IDX_RS:
|
|
return AML_DITTER_I2S_CH5;
|
|
case AML_CH_IDX_LT:
|
|
return AML_DITTER_I2S_CH6;
|
|
case AML_CH_IDX_RT:
|
|
return AML_DITTER_I2S_CH7;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int _save_conf_to_maps(struct aml_channel_map *maps,
|
|
int content_idx, int ch_num, int invert, int ditter)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i=AML_CH_IDX_L; i<AML_CH_IDX_MAX; i++) {
|
|
if (content_idx == maps[i].channel_idx) {
|
|
maps[i].i2s_idx = ch_num/2;
|
|
maps[i].bit_mask |= AML_I2S_CHANNEL_0<<ch_num;
|
|
maps[i].invert |= invert<<ch_num;
|
|
maps[i].ditter |= ditter<<ch_num;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if !defined (BUILDHOSTEXE)
|
|
/* WARNNING: initial function, only need called once!! */
|
|
struct aml_channel_map *data_load_product_config(void)
|
|
{
|
|
struct parser *gParser = NULL;
|
|
char chname[50];
|
|
struct aml_channel_map *maps = NULL;
|
|
int i = 0;
|
|
int find_idx, invert, ditter;
|
|
|
|
maps = aml_audio_malloc(sizeof(struct aml_channel_map)*AML_I2S_CHANNEL_COUNT);
|
|
if (!maps) {
|
|
return NULL;
|
|
} else {
|
|
memset(maps, 0, sizeof(struct aml_channel_map) * AML_I2S_CHANNEL_COUNT);
|
|
maps[AML_CH_IDX_L].channel_idx = AML_CH_IDX_L;
|
|
maps[AML_CH_IDX_R].channel_idx = AML_CH_IDX_R;
|
|
maps[AML_CH_IDX_C].channel_idx = AML_CH_IDX_C;
|
|
maps[AML_CH_IDX_LFE].channel_idx = AML_CH_IDX_LFE;
|
|
maps[AML_CH_IDX_LS].channel_idx = AML_CH_IDX_LS;
|
|
maps[AML_CH_IDX_RS].channel_idx = AML_CH_IDX_RS;
|
|
maps[AML_CH_IDX_LT].channel_idx = AML_CH_IDX_LT;
|
|
maps[AML_CH_IDX_RT].channel_idx = AML_CH_IDX_RT;
|
|
}
|
|
|
|
gParser = aml_config_load(AML_PARAM_AUDIO_HAL_PARAM);
|
|
if (gParser != NULL) {
|
|
// loop of i2s channel [0, 8]
|
|
for (i=0; i<AML_CH_IDX_MAX; i++) {
|
|
strncpy(chname, aml_config_get_str(gParser, AML_SECTION_AUDIO_HAL,
|
|
_get_ch_conf_name(eAmlConfTypeChMap, i), NULL), sizeof(chname)-1);
|
|
invert = aml_config_get_int(gParser, AML_SECTION_AUDIO_HAL,
|
|
_get_ch_conf_name(eAmlConfTypeChInv, i), 0);
|
|
ditter = aml_config_get_int(gParser, AML_SECTION_AUDIO_HAL,
|
|
_get_ch_conf_name(eAmlConfTypeChDit, i), 0);
|
|
find_idx = _name_trans_to_i2s_chidx(chname);
|
|
_save_conf_to_maps(maps, find_idx, i, invert, ditter);
|
|
}
|
|
// unload
|
|
aml_config_unload(gParser);
|
|
}
|
|
|
|
return maps;
|
|
}
|
|
#endif
|
|
|
|
int data_get_channel_i2s_port(
|
|
struct aml_channel_map *map, eChannelContentIdx channelName)
|
|
{
|
|
int i = 0;
|
|
|
|
if (map == NULL) {
|
|
return AML_I2S_PORT_IDX_NULL;
|
|
}
|
|
|
|
for (i=AML_CH_IDX_L; i<AML_CH_IDX_MAX; i++) {
|
|
if (map[i].channel_idx == channelName) {
|
|
AMLOGD("%s: %s <-> i2s-port: %d\n", __func__,
|
|
_get_ch_name(channelName),
|
|
map[i].i2s_idx);
|
|
return map[i].i2s_idx;
|
|
}
|
|
}
|
|
|
|
return AML_I2S_PORT_IDX_NULL;
|
|
}
|
|
|
|
int data_get_channel_bit_mask(
|
|
struct aml_channel_map *map, eChannelContentIdx channelName)
|
|
{
|
|
int i = 0;
|
|
int bit_mask = AML_I2S_CHANNEL_NULL;
|
|
|
|
if (map == NULL) {
|
|
return bit_mask;
|
|
}
|
|
|
|
for (i=AML_CH_IDX_L; i<AML_CH_IDX_MAX; i++) {
|
|
if (map[i].channel_idx == channelName) {
|
|
bit_mask = map[i].bit_mask;
|
|
AMLOGD("%s: %s <-> i2s-bit-mask: 0x%08x\n", __func__,
|
|
_get_ch_name(channelName),
|
|
bit_mask);
|
|
return bit_mask;
|
|
}
|
|
}
|
|
|
|
switch (channelName) {
|
|
case AML_CH_IDX_5_1_ALL:
|
|
case AML_CH_IDX_7_1_ALL:
|
|
case AML_CH_IDX_5_1_2_ALL:
|
|
for (i=0; i<AML_CH_IDX_MAX; i++) {
|
|
bit_mask |= map[i].bit_mask;
|
|
}
|
|
AMLOGD("%s: %s <-> i2s-bit-mask: 0x%08x\n", __func__,
|
|
_get_ch_name(channelName),
|
|
bit_mask);
|
|
return bit_mask;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return bit_mask;
|
|
}
|
|
|
|
eChannelContentIdx data_get_channel_content_idx(
|
|
struct aml_channel_map *map, int bitmask)
|
|
{
|
|
int idx = AML_CH_IDX_NULL;
|
|
int i = 0;
|
|
// int bit_mask = AML_I2S_CHANNEL_NULL;
|
|
|
|
if (map == NULL) {
|
|
return idx;
|
|
}
|
|
|
|
for (i=AML_CH_IDX_L; i<AML_CH_IDX_MAX; i++) {
|
|
if (map[i].bit_mask & bitmask) {
|
|
idx = map[i].channel_idx;
|
|
AMLOGD("%s: i2s-bit-mask: 0x%08x <-> %s\n", __func__,
|
|
bitmask,
|
|
_get_ch_name(idx));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
static int _data_remix_center_to_lr(void *buf, size_t frames, size_t framesz, int channels, int bitmask)
|
|
{
|
|
int16_t center16;
|
|
// int32_t center32;
|
|
int16_t *buf16 = (int16_t *)buf;
|
|
// int32_t *buf32 = (int32_t *)buf;
|
|
int i, tmp;
|
|
|
|
///< TODO: should use bitmask to find the center channel
|
|
if (bitmask == AML_I2S_CHANNEL_NULL)
|
|
return 0;
|
|
|
|
///< TODO: buf is 6ch pcm(L,R,C,lfe,Lr,Rs)
|
|
if (channels != 6) {
|
|
AMLOGD("%s: only support 6 ch now!\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
///< TODO:
|
|
if (framesz != e16BitPerSample) {
|
|
AMLOGD("%s: only support 16bit now!\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
switch (framesz) {
|
|
case e16BitPerSample:
|
|
///< 3/0 input L_out/R_out = = 0.707*(L/R + 0.707*C);
|
|
for (i=0; i<(int)frames; i++) {
|
|
/* save data of center */
|
|
center16 = buf16[channels*i + 2];
|
|
/* calculate L */
|
|
tmp = buf16[channels*i + 0] << 12;
|
|
buf16[channels*i + 0] = _clamp16((MINUS_3_DB_IN_Q19_12 * ((tmp + MINUS_3_DB_IN_Q19_12*center16) >>12))>>12);
|
|
/* calculate R */
|
|
tmp = buf16[channels*i + 1] << 12;
|
|
buf16[channels*i + 1] = _clamp16((MINUS_3_DB_IN_Q19_12 * ((tmp + MINUS_3_DB_IN_Q19_12*center16) >>12))>>12);
|
|
}
|
|
break;
|
|
/* coverity[deadcode]:Reserved for use */
|
|
case e32BitPerSample:
|
|
//TODO:
|
|
break;
|
|
/* coverity[deadcode]:Reserved for use */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _data_remix_all_to_lr(void *buf, size_t frames, size_t framesz, int channels, int bitmask)
|
|
{
|
|
/*
|
|
* --------------------------------------
|
|
* 3/2 input module:
|
|
* L_out = 0.707*(L + 0.707*C + 0.707*Ls)
|
|
* R_out = 0.707*(R + 0.707*C + 0.707*Rs)
|
|
* --------------------------------------
|
|
* our channel sequeces:
|
|
* 0->L
|
|
* 1->R
|
|
* 2->C
|
|
* 3->lfe
|
|
* 4->Ls
|
|
* 5->Rs
|
|
* --------------------------------------
|
|
*/
|
|
int16_t l_16, r_16, c_16, ls_16, rs_16;
|
|
// int16_t l_32, r_32, c_32, ls_32, rs_32;
|
|
int16_t *buf16 = (int16_t *)buf;
|
|
// int32_t *buf32 = (int32_t *)buf;
|
|
int i, tmp;
|
|
|
|
if (!bitmask)
|
|
return 0;
|
|
|
|
///< buf is 6ch pcm(L,R,C,lfe,Lr,Rs)
|
|
if (channels != 6) {
|
|
AMLOGD("%s: only support 6 ch now!\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
///< TODO:
|
|
if (framesz != e16BitPerSample) {
|
|
AMLOGD("%s: only support 16bit now!\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
switch (framesz) {
|
|
case e16BitPerSample:
|
|
for (i = 0; i < (int)frames; i++) {
|
|
/* save l/r/c/ls/rs */
|
|
l_16 = buf16[channels*i + 0];
|
|
r_16 = buf16[channels*i + 1];
|
|
c_16 = buf16[channels*i + 2];
|
|
ls_16 = buf16[channels*i + 4];
|
|
rs_16 = buf16[channels*i + 5];
|
|
/* handle L channel */
|
|
tmp = l_16 << 12;
|
|
buf16[channels*i] =
|
|
_clamp16((MINUS_3_DB_IN_Q19_12 * ((tmp + MINUS_3_DB_IN_Q19_12 * c_16 + MINUS_3_DB_IN_Q19_12 * ls_16) >> 12)) >> 12);
|
|
/* handle R channel */
|
|
tmp = r_16 << 12;
|
|
buf16[channels*i + 1] =
|
|
_clamp16((MINUS_3_DB_IN_Q19_12 * ((tmp + MINUS_3_DB_IN_Q19_12 * c_16 + MINUS_3_DB_IN_Q19_12 * rs_16) >> 12)) >> 12);
|
|
}
|
|
break;
|
|
/* coverity[deadcode]:Reserved for use */
|
|
case e32BitPerSample:
|
|
//TODO:
|
|
break;
|
|
/* coverity[deadcode]:Reserved for use */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int data_remix_to_lr_channel(
|
|
struct aml_channel_map *map,
|
|
void *buf,
|
|
size_t frames,
|
|
size_t framesz,
|
|
int channels,
|
|
eChannelContentIdx chIdx)
|
|
{
|
|
int bit_mask = data_get_channel_bit_mask(map, chIdx);
|
|
|
|
switch (chIdx) {
|
|
case AML_CH_IDX_C:
|
|
return _data_remix_center_to_lr(buf, frames, framesz, channels, bit_mask);
|
|
case AML_CH_IDX_5_1_ALL:
|
|
case AML_CH_IDX_7_1_ALL:
|
|
case AML_CH_IDX_5_1_2_ALL:
|
|
return _data_remix_all_to_lr(buf, frames, framesz, channels, bit_mask);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int data_empty_channels(
|
|
struct aml_channel_map *map,
|
|
void *buf,
|
|
size_t frames,
|
|
size_t framesz,
|
|
int channels,
|
|
int channel_empty_bit_mask)
|
|
{
|
|
int i, j;
|
|
int16_t *buf16 = (int16_t *)buf;
|
|
int32_t *buf32 = (int32_t *)buf;
|
|
|
|
if (!map)
|
|
return 0;
|
|
|
|
switch (framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<channels; j++) {
|
|
if (channel_empty_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
|
|
buf16[channels*i + j] = 0x00;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<channels; j++) {
|
|
if (channel_empty_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
|
|
buf32[channels*i + j] = 0x00;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int data_exchange_i2s_channels(
|
|
void *buf,
|
|
size_t frames,
|
|
size_t framesz,
|
|
size_t channels,
|
|
eI2SDataLineIdx i2s_idx1,
|
|
eI2SDataLineIdx i2s_idx2)
|
|
{
|
|
int i, j;
|
|
int16_t *buf16 = (int16_t *)buf;
|
|
int32_t *buf32 = (int32_t *)buf;
|
|
int16_t tmp16[AML_CH_CNT_PER_PORT];
|
|
int32_t tmp32[AML_CH_CNT_PER_PORT];
|
|
|
|
if (channels < 2*AML_CH_CNT_PER_PORT) {
|
|
AMLOGE("%s: at least 2 i2s port is needed!\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
//printf("\t%d <-> %d\n", i2s_idx1, i2s_idx2);
|
|
|
|
switch (framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<AML_CH_CNT_PER_PORT; j++) {
|
|
tmp16[j] = buf16[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + j];
|
|
buf16[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + j] = buf16[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + j];
|
|
buf16[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + j] = tmp16[j];
|
|
|
|
}
|
|
#if 0
|
|
printf("0x%08x 0x%08x <-> 0x%08x 0x%08x\n\n",
|
|
buf16[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + 0],
|
|
buf16[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + 1],
|
|
buf16[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + 0],
|
|
buf16[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + 1]);
|
|
#endif
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<AML_CH_CNT_PER_PORT; j++) {
|
|
tmp32[j] = buf32[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + j];
|
|
buf32[i*channels + i2s_idx1*AML_CH_CNT_PER_PORT + j] = buf32[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + j];
|
|
buf32[i*channels + i2s_idx2*AML_CH_CNT_PER_PORT + j] = tmp32[j];
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int data_replace_lfe_data(
|
|
void *out_buf,
|
|
size_t out_channels,
|
|
size_t out_framesz,
|
|
void *input_lfe_buffer,
|
|
size_t in_channels,
|
|
size_t in_framesz,
|
|
size_t frames,
|
|
int channel_insert_bit_mask)
|
|
{
|
|
int i, j;
|
|
int16_t *buf_out16 = (int16_t *)out_buf;
|
|
int32_t *buf_out32 = (int32_t *)out_buf;
|
|
int16_t *buf_in16 = (int16_t *)input_lfe_buffer;
|
|
int32_t *buf_in32 = (int32_t *)input_lfe_buffer;
|
|
int lfe_base = 0;
|
|
int lfe_cnt = 0;
|
|
|
|
//TODO:
|
|
if (out_channels != 6) {
|
|
AMLOGE("%s: only support 5.1 channels\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
//TODO:
|
|
if (in_channels != 2) {
|
|
AMLOGE("%s: only support replace 2 channels\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
//TODO: should get from channel_insert_bit_mask
|
|
//case_1: ch2,ch3 are all lfe
|
|
if ((AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3) == channel_insert_bit_mask) {
|
|
lfe_base = 2;
|
|
lfe_cnt = 2;
|
|
}
|
|
//case_1: ch3 is lfe
|
|
if (AML_I2S_CHANNEL_3 == channel_insert_bit_mask) {
|
|
lfe_base = 3;
|
|
lfe_cnt = 1;
|
|
}
|
|
|
|
switch (out_framesz) {
|
|
case e16BitPerSample:
|
|
switch (in_framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<lfe_cnt; j++) {
|
|
buf_out16[out_channels*i + lfe_base + j] = buf_in16[in_channels*i + j];
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<lfe_cnt; j++) {
|
|
buf_out16[out_channels*i + lfe_base + j] = (int16_t)(buf_in16[in_channels*i + j] >> 16);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
switch (in_framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<lfe_cnt; j++) {
|
|
buf_out32[out_channels*i + lfe_base + j] = ((int32_t)buf_in16[in_channels*i + j]) << 16;
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<lfe_cnt; j++) {
|
|
buf_out32[out_channels*i + lfe_base + j] = buf_in32[in_channels*i + j];
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int data_invert_channels(
|
|
void *buf,
|
|
size_t frames,
|
|
size_t framesz,
|
|
int channels,
|
|
int channel_invert_bit_mask)
|
|
{
|
|
int i, j;
|
|
int16_t *buf16 = (int16_t *)buf;
|
|
int32_t *buf32 = (int32_t *)buf;
|
|
int16_t tmp16;
|
|
int32_t tmp32;
|
|
|
|
//_find_index_need_effect(channel_invert_bit_mask);
|
|
switch (framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<channels; j++) {
|
|
if (channel_invert_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
|
|
tmp16 = buf16[channels*i + j];
|
|
buf16[channels*i + j] = -tmp16;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<channels; j++) {
|
|
if (channel_invert_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
|
|
tmp32 = buf32[channels*i + j];
|
|
buf32[channels*i + j] = -tmp32;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int data_concat_channels(
|
|
void *out_buf,
|
|
size_t out_channels,
|
|
size_t out_framesz,
|
|
void *in_buf1, void *in_buf2, void *in_buf3, void *in_buf4,
|
|
size_t in_channels,
|
|
size_t in_framesz,
|
|
size_t frames)
|
|
{
|
|
int i;
|
|
int16_t *buf_out16 = (int16_t *)out_buf;
|
|
int32_t *buf_out32 = (int32_t *)out_buf;
|
|
|
|
int16_t *buf_in1_16 = (int16_t *)in_buf1;
|
|
int16_t *buf_in2_16 = (int16_t *)in_buf2;
|
|
int16_t *buf_in3_16 = (int16_t *)in_buf3;
|
|
int16_t *buf_in4_16 = (int16_t *)in_buf4;
|
|
|
|
int32_t *buf_in1_32 = (int32_t *)in_buf1;
|
|
int32_t *buf_in2_32 = (int32_t *)in_buf2;
|
|
int32_t *buf_in3_32 = (int32_t *)in_buf3;
|
|
int32_t *buf_in4_32 = (int32_t *)in_buf4;
|
|
|
|
if (in_channels != 2 && in_channels != 4 && in_channels != 6 && in_channels != 8) {
|
|
AMLOGE("%s: only support concat 2/4/6/8 channels together!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (in_channels > out_channels) {
|
|
AMLOGE("%s: out_channels %zu < %zu inclannels\n", __func__, out_channels, in_channels);
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (out_framesz) {
|
|
case e16BitPerSample:
|
|
switch (in_framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
if (in_channels >= 2) {
|
|
buf_out16[out_channels*i + 0] = buf_in1_16[2*i + 0];
|
|
buf_out16[out_channels*i + 1] = buf_in1_16[2*i + 1];
|
|
}
|
|
if (in_channels >= 4) {
|
|
buf_out16[out_channels*i + 2] = buf_in2_16[2*i + 0];
|
|
buf_out16[out_channels*i + 3] = buf_in2_16[2*i + 1];
|
|
}
|
|
if (in_channels >= 6) {
|
|
buf_out16[out_channels*i + 4] = buf_in3_16[2*i + 0];
|
|
buf_out16[out_channels*i + 5] = buf_in3_16[2*i + 1];
|
|
}
|
|
if (in_channels >= 8) {
|
|
buf_out16[out_channels*i + 6] = buf_in4_16[2*i + 0];
|
|
buf_out16[out_channels*i + 7] = buf_in4_16[2*i + 1];
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
if (in_channels >= 2) {
|
|
buf_out16[out_channels*i + 0] = (int16_t)(buf_in1_32[2*i + 0]>>16);
|
|
buf_out16[out_channels*i + 1] = (int16_t)(buf_in1_32[2*i + 1]>>16);
|
|
}
|
|
if (in_channels >= 4) {
|
|
buf_out16[out_channels*i + 2] = (int16_t)(buf_in2_32[2*i + 0]>>16);
|
|
buf_out16[out_channels*i + 3] = (int16_t)(buf_in2_32[2*i + 1]>>16);
|
|
}
|
|
if (in_channels >= 6) {
|
|
buf_out16[out_channels*i + 4] = (int16_t)(buf_in3_32[2*i + 0]>>16);
|
|
buf_out16[out_channels*i + 5] = (int16_t)(buf_in3_32[2*i + 1]>>16);
|
|
}
|
|
if (in_channels >= 8) {
|
|
buf_out16[out_channels*i + 6] = (int16_t)(buf_in4_32[2*i + 0]>>16);
|
|
buf_out16[out_channels*i + 7] = (int16_t)(buf_in4_32[2*i + 1]>>16);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
switch (in_framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
if (in_channels >= 2) {
|
|
buf_out32[out_channels*i + 0] = ((int32_t)(buf_in1_16[2*i + 0]))<<16;
|
|
buf_out32[out_channels*i + 1] = ((int32_t)(buf_in1_16[2*i + 1]))<<16;
|
|
}
|
|
if (in_channels >= 4) {
|
|
buf_out32[out_channels*i + 2] = ((int32_t)(buf_in2_16[2*i + 0]))<<16;
|
|
buf_out32[out_channels*i + 3] = ((int32_t)(buf_in2_16[2*i + 1]))<<16;
|
|
}
|
|
if (in_channels >= 6) {
|
|
buf_out32[out_channels*i + 4] = ((int32_t)(buf_in3_16[2*i + 0]))<<16;
|
|
buf_out32[out_channels*i + 5] = ((int32_t)(buf_in3_16[2*i + 1]))<<16;
|
|
}
|
|
if (in_channels >= 8) {
|
|
buf_out32[out_channels*i + 6] = ((int32_t)(buf_in4_16[2*i + 0]))<<16;
|
|
buf_out32[out_channels*i + 7] = ((int32_t)(buf_in4_16[2*i + 1]))<<16;
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
if (in_channels >= 2) {
|
|
buf_out32[out_channels*i + 0] = buf_in1_32[2*i + 0];
|
|
buf_out32[out_channels*i + 1] = buf_in1_32[2*i + 1];
|
|
}
|
|
if (in_channels >= 4) {
|
|
buf_out32[out_channels*i + 2] = buf_in2_32[2*i + 0];
|
|
buf_out32[out_channels*i + 3] = buf_in2_32[2*i + 1];
|
|
}
|
|
if (in_channels >= 6) {
|
|
buf_out32[out_channels*i + 4] = buf_in3_32[2*i + 0];
|
|
buf_out32[out_channels*i + 5] = buf_in3_32[2*i + 1];
|
|
}
|
|
if (in_channels >= 8) {
|
|
buf_out32[out_channels*i + 6] = buf_in4_32[2*i + 0];
|
|
buf_out32[out_channels*i + 7] = buf_in4_32[2*i + 1];
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define COUNT_DITTER_FRAMES (4)
|
|
#define COUNT_DITTER_CHANNELS (8)
|
|
int16_t ditter_8ch_16[COUNT_DITTER_FRAMES*COUNT_DITTER_CHANNELS] = {
|
|
0xffff, 0x0001, 0xffff, 0x0000, 0xffff, 0x0000, 0x0001, 0xffff,
|
|
0x0001, 0xffff, 0x0001, 0xffff, 0x0001, 0xffff, 0xffff, 0x0001,
|
|
0xffff, 0x0001, 0xffff, 0x0000, 0xffff, 0x0001, 0x0000, 0x0000,
|
|
0x0001, 0xffff, 0x0001, 0x0001, 0x0000, 0x0001, 0xffff, 0xffff
|
|
};
|
|
int32_t ditter_8ch_32[COUNT_DITTER_FRAMES*COUNT_DITTER_CHANNELS] = {
|
|
0xffffffff, 0x00000001, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0x00000001, 0xffffffff,
|
|
0x00000001, 0xffffffff, 0x00000001, 0xffffffff, 0x00000001, 0xffffffff, 0xffffffff, 0x00000001,
|
|
0xffffffff, 0x00000001, 0xffffffff, 0x00000000, 0xffffffff, 0x00000001, 0x00000000, 0x00000000,
|
|
0x00000001, 0xffffffff, 0x00000001, 0x00000001, 0x00000000, 0x00000001, 0xffffffff, 0xffffffff
|
|
};
|
|
|
|
int data_add_ditter_to_channels(
|
|
void *buffer,
|
|
size_t frames,
|
|
size_t framesz,
|
|
int channels,
|
|
int channel_ditter_bit_mask)
|
|
{
|
|
int i, j;
|
|
int16_t *buf16 = (int16_t *)buffer;
|
|
int32_t *buf32 = (int32_t *)buffer;
|
|
|
|
int16_t *ditter16;
|
|
int32_t *ditter32;
|
|
|
|
int32_t tmpbuf32;
|
|
int64_t tmpbuf64;
|
|
|
|
if (channels > 8) {
|
|
AMLOGE("%s: only support 5.1.2 ch(8channels) now\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
//TODO: need remove this
|
|
switch (channel_ditter_bit_mask) {
|
|
case AML_CH_IDX_5_1_ALL:
|
|
channel_ditter_bit_mask = AML_I2S_CHANNEL_0|AML_I2S_CHANNEL_1
|
|
|AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3|AML_I2S_CHANNEL_4|AML_I2S_CHANNEL_5;
|
|
break;
|
|
case AML_CH_IDX_7_1_ALL:
|
|
case AML_CH_IDX_5_1_2_ALL:
|
|
channel_ditter_bit_mask = AML_I2S_CHANNEL_0|AML_I2S_CHANNEL_1
|
|
|AML_I2S_CHANNEL_2|AML_I2S_CHANNEL_3|AML_I2S_CHANNEL_4|AML_I2S_CHANNEL_5
|
|
|AML_I2S_CHANNEL_6|AML_I2S_CHANNEL_7;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
ditter16 = &ditter_8ch_16[i%(COUNT_DITTER_FRAMES+1)];
|
|
for (j=0; j<channels; j++) {
|
|
if (channel_ditter_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
|
|
tmpbuf32 = (int32_t)buf16[channels*i + j] + (int32_t)ditter16[j];
|
|
// [-2^15, 2^15-1]
|
|
if (tmpbuf32 > 32767 || tmpbuf32 < -32768) {
|
|
continue;
|
|
} else {
|
|
buf16[channels*i + j] = (int16_t)tmpbuf32;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
ditter32 = &ditter_8ch_32[i%(COUNT_DITTER_FRAMES+1)];
|
|
for (j=0; j<channels; j++) {
|
|
if (channel_ditter_bit_mask & (AML_I2S_CHANNEL_0<<j)) {
|
|
tmpbuf64 = (int64_t)buf32[channels*i + j] + (int64_t)ditter32[j];
|
|
// [-2^31, 2^31-1] // is it right here?
|
|
if (tmpbuf64 > 2147483647 || tmpbuf64 < -2147483647) {
|
|
continue;
|
|
} else {
|
|
buf32[channels*i + j] = (int32_t)tmpbuf64;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int data_extend_channels(
|
|
void *out_buf,
|
|
size_t out_channels,
|
|
size_t out_framesz,
|
|
void *in_buf,
|
|
size_t in_channels,
|
|
size_t in_framesz,
|
|
size_t frames)
|
|
{
|
|
int i, j;
|
|
int16_t *buf_in16 = (int16_t *)in_buf;
|
|
int32_t *buf_in32 = (int32_t *)in_buf;
|
|
int16_t *buf_out16 = (int16_t *)out_buf;
|
|
int32_t *buf_out32 = (int32_t *)out_buf;
|
|
|
|
//TODO: use one interfcae for data_extend_channels/data_extract_channels
|
|
if (out_channels < in_channels) {
|
|
AMLOGE("%s: only support extend channels\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
// initial out buffer first
|
|
memset((char *)out_buf, 0x00, frames*out_channels*out_framesz);
|
|
|
|
switch (out_framesz) {
|
|
case e16BitPerSample:
|
|
switch (in_framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<(int)out_channels; j++) {
|
|
if (j < (int)in_channels) {
|
|
buf_out16[out_channels*i + j] = buf_in16[in_channels*i + j];
|
|
} else {
|
|
buf_out16[out_channels*i + j] = 0x00;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<(int)out_channels; j++) {
|
|
if (j < (int)in_channels) {
|
|
buf_out16[out_channels*i + j] = (int16_t)(buf_in32[in_channels*i + j]>>16);
|
|
} else {
|
|
buf_out16[out_channels*i + j] = 0x00;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
switch (in_framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<(int)out_channels; j++) {
|
|
if (j < (int)in_channels) {
|
|
buf_out32[out_channels*i + j] = ((int32_t)buf_in16[in_channels*i + j])<<16;
|
|
} else {
|
|
buf_out32[out_channels*i + j] = 0x00;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
for (j=0; j<(int)out_channels; j++) {
|
|
if (j < (int)in_channels) {
|
|
buf_out32[out_channels*i + j] = buf_in32[in_channels*i + j];
|
|
} else {
|
|
buf_out32[out_channels*i + j] = 0x00;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int data_extract_channels(
|
|
struct aml_channel_map *map,
|
|
void *out_buf,
|
|
size_t out_channels,
|
|
size_t out_framesz,
|
|
void *in_buf,
|
|
size_t in_channels,
|
|
size_t in_framesz,
|
|
size_t frames,
|
|
int channel_extract_bit_mask)
|
|
{
|
|
int i, k;
|
|
int16_t *buf_in16 = (int16_t *)in_buf;
|
|
int32_t *buf_in32 = (int32_t *)in_buf;
|
|
int16_t *buf_out16 = (int16_t *)out_buf;
|
|
int32_t *buf_out32 = (int32_t *)out_buf;
|
|
int cnt;
|
|
|
|
if (!map)
|
|
return 0;
|
|
|
|
//TODO: use one interfcae for data_extend_channels/data_extract_channels
|
|
if (out_channels > in_channels) {
|
|
AMLOGE("%s: only support extract channels\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
//check param
|
|
cnt = 0;
|
|
for (i=0; i<8; i++)
|
|
if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<i))
|
|
cnt++;
|
|
if (cnt > (int)out_channels) {
|
|
AMLOGE("%s: need extract %d channels, but buf only have %zu chanels\n",
|
|
__func__, cnt, out_channels);
|
|
return -1;
|
|
}
|
|
|
|
switch (out_framesz) {
|
|
case e16BitPerSample:
|
|
switch (in_framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
cnt = 0;
|
|
for (k=0; k<(int)in_channels; k++) {
|
|
if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<k)) {
|
|
buf_out16[out_channels*i + cnt] = buf_in16[in_channels*i + k];
|
|
cnt++;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
cnt = 0;
|
|
for (k=0; k<(int)in_channels; k++) {
|
|
if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<k)) {
|
|
buf_out16[out_channels*i + cnt] = (int16_t)(buf_in32[in_channels*i + k]>>16);
|
|
cnt++;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
switch (in_framesz) {
|
|
case e16BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
cnt = 0;
|
|
for (k=0; k<(int)in_channels; k++) {
|
|
if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<k)) {
|
|
buf_out32[out_channels*i + cnt] = ((int32_t)buf_in16[in_channels*i + k])<<16;
|
|
cnt++;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case e32BitPerSample:
|
|
for (i=0; i<(int)frames; i++) {
|
|
cnt = 0;
|
|
for (k=0; k<(int)in_channels; k++) {
|
|
if (channel_extract_bit_mask & (AML_I2S_CHANNEL_0<<k)) {
|
|
buf_out32[out_channels*i + cnt] = buf_in32[in_channels*i + k];
|
|
cnt++;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int delay[4096];
|
|
static int delay_frame = 1440 * 4;
|
|
static char *delay_start = (char *)delay;
|
|
|
|
int audio_effect_real_lfe_gain(short* buffer, int frame_size, int LPF_Gain)
|
|
{
|
|
int i;
|
|
// short data_left, data_right;
|
|
int output_size = frame_size << 2;
|
|
float gain;
|
|
int32_t tmp_sample;
|
|
memcpy((delay_start + delay_frame), buffer, output_size);
|
|
memcpy(buffer, delay_start, output_size);
|
|
memmove(delay_start, (delay_start + output_size), delay_frame);
|
|
|
|
gain = powf(10, (float)LPF_Gain/20);
|
|
//ALOGE("audio_effect_real_lfe_gain gain %f\n", gain);
|
|
for (i = 0; i < frame_size; i++) {
|
|
tmp_sample = (int32_t)buffer[i * 2 + 0] * gain;
|
|
buffer[i * 2 + 0] = _clamp16(tmp_sample);
|
|
tmp_sample = (int32_t)buffer[i * 2 + 1] * gain;
|
|
buffer[i * 2 + 1] = _clamp16(tmp_sample);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|