/*
* Copyright (C) 2003 - 2016 Sony 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.
*/
#include "ldac.h"
/***************************************************************************************************
Pack and Store from MSB
***************************************************************************************************/
static void pack_store_ldac(
int idata,
int nbits,
STREAM *p_block,
int *p_loc)
{
STREAM *p_bufptr;
register int bpos;
register unsigned int tmp;
p_bufptr = p_block + (*p_loc >> LDAC_LOC_SHIFT);
bpos = *p_loc & LDAC_LOC_MASK;
tmp = (idata << (24-nbits)) & 0xffffff;
tmp >>= bpos;
*p_bufptr++ |= (tmp>>16);
*p_bufptr++ = (tmp>>8) & 0xff;
*p_bufptr = tmp & 0xff;
*p_loc += nbits;
return;
}
/***************************************************************************************************
Pack Frame Header
***************************************************************************************************/
DECLFUNC void pack_frame_header_ldac(
int smplrate_id,
int chconfig_id,
int frame_length,
int frame_status,
STREAM *p_stream)
{
int loc = 0;
pack_store_ldac(LDAC_SYNCWORD, LDAC_SYNCWORDBITS, p_stream, &loc);
pack_store_ldac(smplrate_id, LDAC_SMPLRATEBITS, p_stream, &loc);
pack_store_ldac(chconfig_id, LDAC_CHCONFIG2BITS, p_stream, &loc);
pack_store_ldac(frame_length-1, LDAC_FRAMELEN2BITS, p_stream, &loc);
pack_store_ldac(frame_status, LDAC_FRAMESTATBITS, p_stream, &loc);
return;
}
/***************************************************************************************************
Pack Frame Alignment
***************************************************************************************************/
static void pack_frame_alignment_ldac(
STREAM *p_stream,
int *p_loc,
int nbytes_frame)
{
int i;
int nbytes_filled;
nbytes_filled = nbytes_frame - *p_loc / LDAC_BYTESIZE;
for (i = 0; i < nbytes_filled; i++) {
pack_store_ldac(LDAC_FILLCODE, LDAC_BYTESIZE, p_stream, p_loc);
}
return;
}
/***************************************************************************************************
Pack Byte Alignment
***************************************************************************************************/
#define pack_block_alignment_ldac(p_stream, p_loc) pack_byte_alignment_ldac((p_stream), (p_loc))
static void pack_byte_alignment_ldac(
STREAM *p_stream,
int *p_loc)
{
int nbits_padding;
nbits_padding = ((*p_loc + LDAC_BYTESIZE - 1) / LDAC_BYTESIZE) * LDAC_BYTESIZE - *p_loc;
if (nbits_padding > 0) {
pack_store_ldac(0, nbits_padding, p_stream, p_loc);
}
return;
}
/***************************************************************************************************
Pack Band Info
***************************************************************************************************/
static void pack_band_info_ldac(
AB *p_ab,
STREAM *p_stream,
int *p_loc)
{
pack_store_ldac(p_ab->nbands-LDAC_BAND_OFFSET, LDAC_NBANDBITS, p_stream, p_loc);
pack_store_ldac(LDAC_FALSE, LDAC_FLAGBITS, p_stream, p_loc);
return;
}
/***************************************************************************************************
Pack Gradient Data
***************************************************************************************************/
static void pack_gradient_ldac(
AB *p_ab,
STREAM *p_stream,
int *p_loc)
{
pack_store_ldac(p_ab->grad_mode, LDAC_GRADMODEBITS, p_stream, p_loc);
if (p_ab->grad_mode == LDAC_MODE_0) {
pack_store_ldac(p_ab->grad_qu_l, LDAC_GRADQU0BITS, p_stream, p_loc);
pack_store_ldac(p_ab->grad_qu_h-1, LDAC_GRADQU0BITS, p_stream, p_loc);
pack_store_ldac(p_ab->grad_os_l, LDAC_GRADOSBITS, p_stream, p_loc);
pack_store_ldac(p_ab->grad_os_h, LDAC_GRADOSBITS, p_stream, p_loc);
}
else {
pack_store_ldac(p_ab->grad_qu_l, LDAC_GRADQU1BITS, p_stream, p_loc);
pack_store_ldac(p_ab->grad_os_l, LDAC_GRADOSBITS, p_stream, p_loc);
}
pack_store_ldac(p_ab->nadjqus, LDAC_NADJQUBITS, p_stream, p_loc);
return;
}
/***************************************************************************************************
Subfunction: Pack Scale Factor Data - Mode 0
***************************************************************************************************/
static void pack_scale_factor_0_ldac(
AC *p_ac,
STREAM *p_stream,
int *p_loc)
{
HCENC *p_hcsf;
int iqu;
int nqus = p_ac->p_ab->nqus;
int dif, val0, val1;
const unsigned char *p_tbl;
pack_store_ldac(p_ac->sfc_bitlen-LDAC_MINSFCBLEN_0, LDAC_SFCBLENBITS, p_stream, p_loc);
pack_store_ldac(p_ac->sfc_offset, LDAC_IDSFBITS, p_stream, p_loc);
pack_store_ldac(p_ac->sfc_weight, LDAC_SFCWTBLBITS, p_stream, p_loc);
p_tbl = gaa_sfcwgt_ldac[p_ac->sfc_weight];
val0 = p_ac->a_idsf[0] + p_tbl[0];
pack_store_ldac(val0-p_ac->sfc_offset, p_ac->sfc_bitlen, p_stream, p_loc);
p_hcsf = ga_hcenc_sf0_ldac + (p_ac->sfc_bitlen-LDAC_MINSFCBLEN_0);
for (iqu = 1; iqu < nqus; iqu++) {
val1 = p_ac->a_idsf[iqu] + p_tbl[iqu];
dif = (val1 - val0) & p_hcsf->mask;
pack_store_ldac(hc_word_ldac(p_hcsf->p_tbl+dif), hc_len_ldac(p_hcsf->p_tbl+dif), p_stream, p_loc);
val0 = val1;
}
return;
}
/***************************************************************************************************
Subfunction: Pack Scale Factor Data - Mode 1
***************************************************************************************************/
static void pack_scale_factor_1_ldac(
AC *p_ac,
STREAM *p_stream,
int *p_loc)
{
int iqu;
int nqus = p_ac->p_ab->nqus;
const unsigned char *p_tbl;
pack_store_ldac(p_ac->sfc_bitlen-LDAC_MINSFCBLEN_1, LDAC_SFCBLENBITS, p_stream, p_loc);
if (p_ac->sfc_bitlen > 4) {
for (iqu = 0; iqu < nqus; iqu++) {
pack_store_ldac(p_ac->a_idsf[iqu], LDAC_IDSFBITS, p_stream, p_loc);
}
}
else {
pack_store_ldac(p_ac->sfc_offset, LDAC_IDSFBITS, p_stream, p_loc);
pack_store_ldac(p_ac->sfc_weight, LDAC_SFCWTBLBITS, p_stream, p_loc);
p_tbl = gaa_sfcwgt_ldac[p_ac->sfc_weight];
for (iqu = 0; iqu < nqus; iqu++) {
pack_store_ldac(p_ac->a_idsf[iqu]+p_tbl[iqu]-p_ac->sfc_offset, p_ac->sfc_bitlen, p_stream, p_loc);
}
}
return;
}
/***************************************************************************************************
Subfunction: Pack Scale Factor Data - Mode 2
***************************************************************************************************/
static void pack_scale_factor_2_ldac(
AC *p_ac,
STREAM *p_stream,
int *p_loc)
{
HCENC *p_hcsf;
int iqu;
int nqus = p_ac->p_ab->nqus;
int dif;
pack_store_ldac(p_ac->sfc_bitlen-LDAC_MINSFCBLEN_2, LDAC_SFCBLENBITS, p_stream, p_loc);
p_hcsf = ga_hcenc_sf1_ldac + (p_ac->sfc_bitlen-LDAC_MINSFCBLEN_2);
for (iqu = 0; iqu < nqus; iqu++) {
dif = (p_ac->a_idsf[iqu] - p_ac->p_ab->ap_ac[0]->a_idsf[iqu]) & p_hcsf->mask;
pack_store_ldac(hc_word_ldac(p_hcsf->p_tbl+dif), hc_len_ldac(p_hcsf->p_tbl+dif), p_stream, p_loc);
}
return;
}
/***************************************************************************************************
Pack Scale Factor Data
***************************************************************************************************/
static void pack_scale_factor_ldac(
AC *p_ac,
STREAM *p_stream,
int *p_loc)
{
int sfc_mode = p_ac->sfc_mode;
pack_store_ldac(sfc_mode, LDAC_SFCMODEBITS, p_stream, p_loc);
if (p_ac->ich == 0) {
if (sfc_mode == LDAC_MODE_0) {
pack_scale_factor_0_ldac(p_ac, p_stream, p_loc);
}
else {
pack_scale_factor_1_ldac(p_ac, p_stream, p_loc);
}
}
else {
if (sfc_mode == LDAC_MODE_0) {
pack_scale_factor_0_ldac(p_ac, p_stream, p_loc);
}
else {
pack_scale_factor_2_ldac(p_ac, p_stream, p_loc);
}
}
return;
}
/***************************************************************************************************
Pack Spectrum Data
***************************************************************************************************/
static void pack_spectrum_ldac(
AC *p_ac,
STREAM *p_stream,
int *p_loc)
{
int iqu, isp, i;
int lsp, hsp;
int nqus = p_ac->p_ab->nqus;
int nsps, idwl1, wl, val;
for (iqu = 0; iqu < nqus; iqu++) {
lsp = ga_isp_ldac[iqu];
hsp = ga_isp_ldac[iqu+1];
nsps = ga_nsps_ldac[iqu];
idwl1 = p_ac->a_idwl1[iqu];
wl = ga_wl_ldac[idwl1];
if (idwl1 == 1) {
isp = lsp;
if (nsps == 2) {
val = (p_ac->a_qspec[isp ]+1) << 2;
val += (p_ac->a_qspec[isp+1]+1);
pack_store_ldac(ga_2dimenc_spec_ldac[val], LDAC_2DIMSPECBITS, p_stream, p_loc);
}
else {
for (i = 0; i < nsps>>2; i++, isp+=4) {
val = (p_ac->a_qspec[isp ]+1) << 6;
val += (p_ac->a_qspec[isp+1]+1) << 4;
val += (p_ac->a_qspec[isp+2]+1) << 2;
val += (p_ac->a_qspec[isp+3]+1);
pack_store_ldac(ga_4dimenc_spec_ldac[val], LDAC_4DIMSPECBITS, p_stream, p_loc);
}
}
}
else {
for (isp = lsp; isp < hsp; isp++) {
pack_store_ldac(p_ac->a_qspec[isp], wl, p_stream, p_loc);
}
}
}
return;
}
/***************************************************************************************************
Pack Residual Data
***************************************************************************************************/
static void pack_residual_ldac(
AC *p_ac,
STREAM *p_stream,
int *p_loc)
{
int iqu, isp;
int lsp, hsp;
int nqus = p_ac->p_ab->nqus;
int idwl2, wl;
for (iqu = 0; iqu < nqus; iqu++) {
idwl2 = p_ac->a_idwl2[iqu];
if (idwl2 > 0) {
lsp = ga_isp_ldac[iqu];
hsp = ga_isp_ldac[iqu+1];
wl = ga_wl_ldac[idwl2];
for (isp = lsp; isp < hsp; isp++) {
pack_store_ldac(p_ac->a_rspec[isp], wl, p_stream, p_loc);
}
}
}
return;
}
/***************************************************************************************************
Pack Audio Block
***************************************************************************************************/
static int pack_audio_block_ldac(
AB *p_ab,
STREAM *p_stream,
int *p_loc)
{
AC *p_ac;
int ich;
int nchs = p_ab->blk_nchs;
int nbits_band, nbits_grad, a_nbits_scfc[2], a_nbits_spec[2], nbits_used;
int loc;
for (ich = 0; ich < 2; ich++) {
a_nbits_scfc[ich] = 0;
a_nbits_spec[ich] = 0;
}
loc = *p_loc;
pack_band_info_ldac(p_ab, p_stream, p_loc);
nbits_band = *p_loc - loc;
loc = *p_loc;
pack_gradient_ldac(p_ab, p_stream, p_loc);
nbits_grad = *p_loc - loc;
nbits_used = nbits_band + nbits_grad;
for (ich = 0; ich < nchs; ich++) {
p_ac = p_ab->ap_ac[ich];
loc = *p_loc;
pack_scale_factor_ldac(p_ac, p_stream, p_loc);
a_nbits_scfc[ich] = *p_loc - loc;
loc = *p_loc;
pack_spectrum_ldac(p_ac, p_stream, p_loc);
a_nbits_spec[ich] = *p_loc - loc;
loc = *p_loc;
pack_residual_ldac(p_ac, p_stream, p_loc);
a_nbits_spec[ich] += *p_loc - loc;
nbits_used += a_nbits_scfc[ich] + a_nbits_spec[ich];
}
if (nbits_used > p_ab->nbits_used) {
*p_ab->p_error_code = LDAC_ERR_BIT_PACKING;
return LDAC_FALSE;
}
else if (nbits_used < p_ab->nbits_used) {
*p_ab->p_error_code = LDAC_ERR_BIT_PACKING;
return LDAC_FALSE;
}
return LDAC_TRUE;
}
/***************************************************************************************************
Pack Raw Data Frame
***************************************************************************************************/
DECLFUNC int pack_raw_data_frame_ldac(
SFINFO *p_sfinfo,
STREAM *p_stream,
int *p_loc,
int *p_nbytes_used)
{
CFG *p_cfg = &p_sfinfo->cfg;
AB *p_ab = p_sfinfo->p_ab;
int ibk;
int nbks = gaa_block_setting_ldac[p_cfg->chconfig_id][1];
for (ibk = 0; ibk < nbks; ibk++) {
if (!pack_audio_block_ldac(p_ab, p_stream, p_loc)) {
return LDAC_ERR_PACK_BLOCK_FAILED;
}
pack_block_alignment_ldac(p_stream, p_loc);
p_ab++;
}
pack_frame_alignment_ldac(p_stream, p_loc, p_cfg->frame_length);
*p_nbytes_used = *p_loc / LDAC_BYTESIZE;
return LDAC_ERR_NONE;
}
/***************************************************************************************************
Pack Null Data Frame
***************************************************************************************************/
static const int sa_null_data_size_ldac[2] = {
11, 15,
};
static const STREAM saa_null_data_ldac[2][15] = {
{0x07, 0xa0, 0x16, 0x00, 0x20, 0xad, 0x51, 0x45, 0x14, 0x50, 0x49},
{0x07, 0xa0, 0x0a, 0x00, 0x20, 0xad, 0x51, 0x41, 0x24, 0x93, 0x00, 0x28, 0xa0, 0x92, 0x49},
};
DECLFUNC int pack_null_data_frame_ldac(
SFINFO *p_sfinfo,
STREAM *p_stream,
int *p_loc,
int *p_nbytes_used)
{
CFG *p_cfg = &p_sfinfo->cfg;
AB *p_ab = p_sfinfo->p_ab;
int ibk;
int nbks = gaa_block_setting_ldac[p_cfg->chconfig_id][1];
int blk_type, size, offset = 0;
for (ibk = 0; ibk < nbks; ibk++) {
blk_type = p_ab->blk_type;
size = sa_null_data_size_ldac[blk_type];
copy_data_ldac(saa_null_data_ldac[blk_type], p_stream+offset, size*sizeof(STREAM));
*p_loc += size*LDAC_BYTESIZE;
offset += size;
p_ab++;
}
if (p_cfg->frame_length < offset) {
return LDAC_ERR_PACK_BLOCK_FAILED;
}
pack_frame_alignment_ldac(p_stream, p_loc, p_cfg->frame_length);
*p_nbytes_used = *p_loc / LDAC_BYTESIZE;
return LDAC_ERR_NONE;
}