180 lines
5.8 KiB
C++
180 lines
5.8 KiB
C++
/*
|
|
* MPVQ.cpp
|
|
*
|
|
* Copyright 2019 HIMSA II K/S - www.himsa.dk. Represented by EHIMA - www.ehima.com
|
|
*
|
|
* 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 "MPVQ.hpp"
|
|
#include <cstdbool>
|
|
|
|
#include "SnsQuantizationTables.hpp"
|
|
|
|
namespace Lc3Dec
|
|
{
|
|
|
|
// declare local helper functions
|
|
void mind2vec_tab ( short dim_in, /* i: dimension */
|
|
short k_max_local, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind, /* i: MPVQ-index */
|
|
short *vec_out, /* o: pulse train */
|
|
unsigned int MPVQ_offsets [][11] /* i: offset matrix */
|
|
);
|
|
|
|
void mind2vec_one( short k_val_in, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign -1, 1 */
|
|
short *vec_out /* o: updated pulse train */
|
|
);
|
|
|
|
|
|
short setval_update_sign (
|
|
short k_delta, /* i */
|
|
short k_max_local_in, /* i */
|
|
short *leading_sign, /* i/o */
|
|
unsigned int *ind_in, /* i/o */
|
|
short *vec_out /* i/o */
|
|
);
|
|
|
|
short get_lead_sign(unsigned int *ind_in );
|
|
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
|
|
void MPVQdeenum(uint8_t dim_in, /* i : dimension of vec_out */
|
|
uint8_t k_val_in, /* i : number of unit pulses */
|
|
int16_t LS_ind, /* i : leading sign index */
|
|
int32_t MPVQ_ind, /* i : MPVQ shape index */
|
|
int16_t *vec_out /* o : PVQ integer pulse train */
|
|
)
|
|
{
|
|
for (uint8_t i=0; i < dim_in; i++)
|
|
{
|
|
vec_out[i] = 0;
|
|
}
|
|
short leading_sign = 1;
|
|
if ( LS_ind != 0 ){
|
|
leading_sign = -1;
|
|
}
|
|
mind2vec_tab ( dim_in,
|
|
k_val_in,
|
|
leading_sign,
|
|
MPVQ_ind,
|
|
vec_out,
|
|
MPVQ_offsets );
|
|
}
|
|
|
|
void mind2vec_tab ( short dim_in, /* i: dimension */
|
|
short k_max_local, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind, /* i: MPVQ-index */
|
|
short *vec_out, /* o: pulse train */
|
|
unsigned int MPVQ_offsets [][11] /* i: offset matrix */
|
|
)
|
|
{
|
|
/* init */
|
|
unsigned int* h_row_ptr = &(MPVQ_offsets[(dim_in-1)][0]);
|
|
short k_acc = k_max_local;
|
|
/* loop over positions */
|
|
for (uint8_t pos = 0; pos < dim_in; pos++)
|
|
{
|
|
short k_delta;
|
|
if (ind != 0)
|
|
{
|
|
k_acc = k_max_local;;
|
|
unsigned int UL_tmp_offset = h_row_ptr[k_acc];
|
|
bool wrap_flag = (ind < UL_tmp_offset ) ;
|
|
unsigned int UL_diff=0;
|
|
if (!wrap_flag)
|
|
{
|
|
// Note: due to android build using a integer-overflow sanitizer, we have to avoid
|
|
// computing the following difference when ind < UL_tmp_offset
|
|
UL_diff = ind - UL_tmp_offset;
|
|
}
|
|
while (wrap_flag)
|
|
{
|
|
k_acc--;
|
|
wrap_flag = (ind < h_row_ptr[k_acc]);
|
|
if (!wrap_flag)
|
|
{
|
|
// Note: due to android build using a integer-overflow sanitizer, we have to avoid
|
|
// computing the following difference when ind < UL_tmp_offset
|
|
UL_diff = ind - h_row_ptr[k_acc];
|
|
}
|
|
}
|
|
ind = UL_diff;
|
|
k_delta = k_max_local - k_acc;
|
|
}
|
|
else
|
|
{
|
|
mind2vec_one(k_max_local, leading_sign, &vec_out[pos]);
|
|
break;
|
|
}
|
|
k_max_local = setval_update_sign(
|
|
k_delta,
|
|
k_max_local,
|
|
&leading_sign,
|
|
&ind,
|
|
&vec_out[pos]);
|
|
h_row_ptr -= 11; /* reduce dimension in MPVQ_offsets table */
|
|
}
|
|
}
|
|
|
|
|
|
void mind2vec_one( short k_val_in, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign -1, 1 */
|
|
short *vec_out /* o: updated pulse train */
|
|
)
|
|
{
|
|
short amp = k_val_in;
|
|
if ( leading_sign < 0 )
|
|
{
|
|
amp = -k_val_in ;
|
|
}
|
|
*vec_out = amp;
|
|
}
|
|
|
|
short setval_update_sign (
|
|
short k_delta, /* i */
|
|
short k_max_local_in, /* i */
|
|
short *leading_sign, /* i/o */
|
|
unsigned int *ind_in, /* i/o; needed to change type compared to spec */
|
|
short *vec_out /* i/o */
|
|
)
|
|
{
|
|
short k_max_local_out = k_max_local_in;
|
|
if (k_delta != 0)
|
|
{
|
|
mind2vec_one(k_delta, *leading_sign, vec_out);
|
|
*leading_sign = get_lead_sign( ind_in );
|
|
k_max_local_out -= k_delta ;
|
|
}
|
|
return k_max_local_out;
|
|
}
|
|
|
|
short get_lead_sign(unsigned int *ind ) // renamed "ind_in" from spec to just "ind" (as already found by yao.wang 28.06.2019)
|
|
{
|
|
short leading_sign = +1;
|
|
if ( ((*ind)&0x1 ) != 0 )
|
|
{
|
|
leading_sign = -1;
|
|
}
|
|
(*ind) = (*ind >> 1);
|
|
return leading_sign;
|
|
}
|
|
|
|
}//namespace Lc3Dec
|