From 62649d833bdb35eb86cff0c9c16e96e45042df91 Mon Sep 17 00:00:00 2001 From: Chris Waddell <quic_cwaddell@quicinc.com> Date: Wed, 19 Oct 2022 17:18:43 +0100 Subject: [PATCH] Add encoder for aptX and encoder for aptX HD source code. Bug: 226572369 Test: In follow-up CL Change-Id: I3cc67c9f1466fc8518c81160fbf3034b7ae6807b --- .../encoder_for_aptx/include/aptXbtenc.h | 52 + .../embdrv/encoder_for_aptx/src/AptxEncoder.h | 80 + .../encoder_for_aptx/src/AptxParameters.h | 247 +++ .../embdrv/encoder_for_aptx/src/AptxTables.h | 424 +++++ system/embdrv/encoder_for_aptx/src/CBStruct.h | 28 + .../encoder_for_aptx/src/CodewordPacker.h | 59 + .../encoder_for_aptx/src/DitherGenerator.h | 102 ++ .../encoder_for_aptx/src/ProcessSubband.c | 43 + system/embdrv/encoder_for_aptx/src/Qmf.h | 142 ++ system/embdrv/encoder_for_aptx/src/QmfConv.c | 327 ++++ .../encoder_for_aptx/src/QuantiseDifference.c | 711 +++++++++ .../embdrv/encoder_for_aptx/src/Quantiser.h | 27 + .../encoder_for_aptx/src/SubbandFunctions.h | 184 +++ .../src/SubbandFunctionsCommon.h | 515 +++++++ .../encoder_for_aptx/src/SyncInserter.h | 217 +++ .../embdrv/encoder_for_aptx/src/aptXbtenc.c | 218 +++ .../embdrv/encoder_for_aptx/src/swversion.h | 8 + .../encoder_for_aptxhd/include/aptXHDbtenc.h | 49 + .../encoder_for_aptxhd/src/AptxEncoder.h | 87 ++ .../encoder_for_aptxhd/src/AptxParameters.h | 248 +++ .../encoder_for_aptxhd/src/AptxTables.h | 1365 +++++++++++++++++ .../embdrv/encoder_for_aptxhd/src/CBStruct.h | 28 + .../encoder_for_aptxhd/src/CodewordPacker.h | 50 + .../encoder_for_aptxhd/src/DitherGenerator.h | 101 ++ .../encoder_for_aptxhd/src/ProcessSubband.c | 43 + system/embdrv/encoder_for_aptxhd/src/Qmf.h | 150 ++ .../embdrv/encoder_for_aptxhd/src/QmfConv.c | 337 ++++ .../src/QuantiseDifference.c | 763 +++++++++ .../embdrv/encoder_for_aptxhd/src/Quantiser.h | 27 + .../encoder_for_aptxhd/src/SubbandFunctions.h | 183 +++ .../src/SubbandFunctionsCommon.h | 520 +++++++ .../encoder_for_aptxhd/src/SyncInserter.h | 114 ++ .../encoder_for_aptxhd/src/aptXHDbtenc.c | 179 +++ .../embdrv/encoder_for_aptxhd/src/swversion.h | 8 + 34 files changed, 7636 insertions(+) create mode 100644 system/embdrv/encoder_for_aptx/include/aptXbtenc.h create mode 100644 system/embdrv/encoder_for_aptx/src/AptxEncoder.h create mode 100644 system/embdrv/encoder_for_aptx/src/AptxParameters.h create mode 100644 system/embdrv/encoder_for_aptx/src/AptxTables.h create mode 100644 system/embdrv/encoder_for_aptx/src/CBStruct.h create mode 100644 system/embdrv/encoder_for_aptx/src/CodewordPacker.h create mode 100644 system/embdrv/encoder_for_aptx/src/DitherGenerator.h create mode 100644 system/embdrv/encoder_for_aptx/src/ProcessSubband.c create mode 100644 system/embdrv/encoder_for_aptx/src/Qmf.h create mode 100644 system/embdrv/encoder_for_aptx/src/QmfConv.c create mode 100644 system/embdrv/encoder_for_aptx/src/QuantiseDifference.c create mode 100644 system/embdrv/encoder_for_aptx/src/Quantiser.h create mode 100644 system/embdrv/encoder_for_aptx/src/SubbandFunctions.h create mode 100644 system/embdrv/encoder_for_aptx/src/SubbandFunctionsCommon.h create mode 100644 system/embdrv/encoder_for_aptx/src/SyncInserter.h create mode 100644 system/embdrv/encoder_for_aptx/src/aptXbtenc.c create mode 100644 system/embdrv/encoder_for_aptx/src/swversion.h create mode 100644 system/embdrv/encoder_for_aptxhd/include/aptXHDbtenc.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/AptxEncoder.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/AptxParameters.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/AptxTables.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/CBStruct.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/CodewordPacker.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/DitherGenerator.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/ProcessSubband.c create mode 100644 system/embdrv/encoder_for_aptxhd/src/Qmf.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/QmfConv.c create mode 100644 system/embdrv/encoder_for_aptxhd/src/QuantiseDifference.c create mode 100644 system/embdrv/encoder_for_aptxhd/src/Quantiser.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/SubbandFunctions.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/SubbandFunctionsCommon.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/SyncInserter.h create mode 100644 system/embdrv/encoder_for_aptxhd/src/aptXHDbtenc.c create mode 100644 system/embdrv/encoder_for_aptxhd/src/swversion.h diff --git a/system/embdrv/encoder_for_aptx/include/aptXbtenc.h b/system/embdrv/encoder_for_aptx/include/aptXbtenc.h new file mode 100644 index 00000000000..47aa29309c6 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/include/aptXbtenc.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------------ + * + * This file exposes a public interface to allow clients to invoke aptX + * encoding on 4 new PCM samples, generating 2 new codeword (one for the + * left channel and one for the right channel). + * + *----------------------------------------------------------------------------*/ + +#ifndef APTXBTENC_H +#define APTXBTENC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _DLLEXPORT +#define APTXBTENCEXPORT __declspec(dllexport) +#else +#define APTXBTENCEXPORT +#endif + +/* SizeofAptxbtenc returns the size (in byte) of the memory + * allocation required to store the state of the encoder */ +APTXBTENCEXPORT int SizeofAptxbtenc(void); + +/* aptxbtenc_version can be used to extract the version number + * of the aptX encoder */ +APTXBTENCEXPORT const char* aptxbtenc_version(void); + +/* aptxbtenc_init is used to initialise the encoder structure. + * _state should be a pointer to the encoder structure (stereo). + * endian represent the endianness of the output data + * (0=little endian. Big endian otherwise) + * The function returns 1 if an error occurred during the initialisation. + * The function returns 0 if no error occurred during the initialisation. */ +APTXBTENCEXPORT int aptxbtenc_init(void* _state, short endian); + +/* aptxbtenc_setsync_mode is used to initialise the sync mode in the encoder state structure. + * _state should be a pointer to the encoder structure (stereo, though strictly-speaking it is dual channel). + * 'sync_mode' is an enumerated type {stereo=0, dualmono=1, no_sync=2} + * The function returns 0 if no error occurred during the initialisation. */ +APTXBTENCEXPORT int aptxbtenc_setsync_mode(void* _state, int32_t sync_mode); + +/* StereoEncode will take 8 audio samples (16-bit per sample) + * and generate one 32-bit codeword with autosync inserted. */ +APTXBTENCEXPORT int aptxbtenc_encodestereo(void* _state, void* _pcmL, void* _pcmR, void* _buffer); + +#ifdef __cplusplus +} // /extern "C" +#endif + +#endif //APTXBTENC_H diff --git a/system/embdrv/encoder_for_aptx/src/AptxEncoder.h b/system/embdrv/encoder_for_aptx/src/AptxEncoder.h new file mode 100644 index 00000000000..81b75d04a5e --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/AptxEncoder.h @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------------ + * + * All declarations relevant for aptxEncode. This function allows clients + * to invoke bt-aptX encoding on 4 new PCM samples, + * generating 4 new quantised codes. A separate function allows the + * packing of the 4 codes into a 16-bit word. + * + *----------------------------------------------------------------------------*/ + +#ifndef APTXENCODER_H +#define APTXENCODER_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + +#include "AptxParameters.h" +#include "DitherGenerator.h" +#include "Quantiser.h" +#include "SubbandFunctionsCommon.h" +#include "Qmf.h" + + + /* Function to carry out a single-channel aptX encode on 4 new PCM samples */ +XBT_INLINE_ void aptxEncode(int32_t pcm[4], Qmf_storage* Qmf_St, Encoder_data* EncoderDataPt) +{ + int32_t predVals[4]; + int32_t qCodes[4]; + int32_t aqmfOutputs[4]; + + /* Extract the previous predicted values and quantised codes into arrays */ + for (int i = 0; i < 4; i++) + { + predVals[i] = EncoderDataPt->m_SubbandData[i].m_predData.m_predVal; + qCodes[i] = EncoderDataPt->m_qdata[i].qCode; + } + + /* Update codeword history, then generate new dither values. */ + EncoderDataPt->m_codewordHistory = xbtEncupdateCodewordHistory(qCodes, EncoderDataPt->m_codewordHistory); + EncoderDataPt->m_dithSyncRandBit = xbtEncgenerateDither(EncoderDataPt->m_codewordHistory, EncoderDataPt->m_ditherOutputs); + + /* Run the analysis QMF */ + QmfAnalysisFilter(pcm, Qmf_St, predVals, aqmfOutputs); + + /* Run the quantiser for each subband */ + quantiseDifferenceLL(aqmfOutputs[0], EncoderDataPt->m_ditherOutputs[0], EncoderDataPt->m_SubbandData[0].m_iqdata.delta, &EncoderDataPt->m_qdata[0]); + quantiseDifferenceLH(aqmfOutputs[1], EncoderDataPt->m_ditherOutputs[1], EncoderDataPt->m_SubbandData[1].m_iqdata.delta, &EncoderDataPt->m_qdata[1]); + quantiseDifferenceHL(aqmfOutputs[2], EncoderDataPt->m_ditherOutputs[2], EncoderDataPt->m_SubbandData[2].m_iqdata.delta, &EncoderDataPt->m_qdata[2]); + quantiseDifferenceHH(aqmfOutputs[3], EncoderDataPt->m_ditherOutputs[3], EncoderDataPt->m_SubbandData[3].m_iqdata.delta, &EncoderDataPt->m_qdata[3]); +} + +XBT_INLINE_ void aptxPostEncode(Encoder_data* EncoderDataPt) +{ + /* Run the remaining subband processing for each subband */ + /* Manual inlining on the 4 subband */ + processSubbandLL(EncoderDataPt->m_qdata[0].qCode, + EncoderDataPt->m_ditherOutputs[0], + &EncoderDataPt->m_SubbandData[0], + &EncoderDataPt->m_SubbandData[0].m_iqdata); + + processSubband(EncoderDataPt->m_qdata[1].qCode, + EncoderDataPt->m_ditherOutputs[1], + &EncoderDataPt->m_SubbandData[1], + &EncoderDataPt->m_SubbandData[1].m_iqdata); + + processSubbandHL(EncoderDataPt->m_qdata[2].qCode, + EncoderDataPt->m_ditherOutputs[2], + &EncoderDataPt->m_SubbandData[2], + &EncoderDataPt->m_SubbandData[2].m_iqdata); + + processSubband(EncoderDataPt->m_qdata[3].qCode, + EncoderDataPt->m_ditherOutputs[3], + &EncoderDataPt->m_SubbandData[3], + &EncoderDataPt->m_SubbandData[3].m_iqdata); +} + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //APTXENCODER_H diff --git a/system/embdrv/encoder_for_aptx/src/AptxParameters.h b/system/embdrv/encoder_for_aptx/src/AptxParameters.h new file mode 100644 index 00000000000..f8a7d04532a --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/AptxParameters.h @@ -0,0 +1,247 @@ +/*------------------------------------------------------------------------------ + * + * General shared aptX parameters. + * + *----------------------------------------------------------------------------*/ + +#ifndef APTXPARAMETERS_H +#define APTXPARAMETERS_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +#include <stdint.h> +#include "CBStruct.h" + +#if defined _MSC_VER + #define XBT_INLINE_ inline + #define _STDQMFOUTERCOEFF 1 +#elif defined __clang__ + #define XBT_INLINE_ static inline + #define _STDQMFOUTERCOEFF 1 +#elif defined __GNUC__ + #define XBT_INLINE_ inline + #define _STDQMFOUTERCOEFF 1 +#else + #define XBT_INLINE_ static + #define _STDQMFOUTERCOEFF 1 +#endif + + +/* Signed saturate to a 24bit value */ +XBT_INLINE_ int32_t ssat24(int32_t val) +{ + if (val > 8388607) val = 8388607; + if (val < -8388608) val = -8388608; + return val; +} + +typedef union u_reg64 +{ + uint64_t u64; + int64_t s64; + struct s_u32 + { +#ifdef __BIGENDIAN + uint32_t h; + uint32_t l; +#else + uint32_t l; + uint32_t h; +#endif + } u32; + + struct s_s32 + { +#ifdef __BIGENDIAN + int32_t h; + int32_t l; +#else + int32_t l; + int32_t h; +#endif + } s32; +} reg64_t; + +typedef union u_reg32 +{ + uint32_t u32; + int32_t s32; + + struct s_u16 + { +#ifdef __BIGENDIAN + uint16_t h; + uint16_t l; +#else + uint16_t l; + uint16_t h; +#endif + } u16; + struct s_s16 + { +#ifdef __BIGENDIAN + int16_t h; + int16_t l; +#else + int16_t l; + int16_t h; +#endif + } s16; +} reg32_t; + +/* Each aptX enc/dec round consumes/produces 4 PCM samples */ +static const uint32_t numPcmSamples = 4; + +/* Symbolic constants for PCM data indicies. */ +enum {FirstPcm=0, SecondPcm=1, ThirdPcm=2, FourthPcm=3}; + +/* Symbolic constants for sync modes. */ +enum {stereo=0, dualmono=1, no_sync=2}; + +/* Number of subbands is fixed at 4 */ +#define NUMSUBBANDS 4 + +/* Symbolic constants for subband identification. */ +typedef enum {LL=0, LH=1, HL=2, HH=3} bands; + +/* Structure declaration to bind a set of subband parameters */ +typedef struct +{ + const int32_t* threshTable; + const int32_t* threshTable_sl1; + const int32_t* dithTable; + const int32_t* dithTable_sh1; + const int32_t* minusLambdaDTable; + const int32_t* incrTable; + int32_t numBits; + int32_t maxLogDelta; + int32_t minLogDelta; + int32_t numZeros; +} SubbandParameters; + +/* Struct required for the polecoeffcalculator function of bt-aptX encoder and decoder*/ +/* Size of structure: 16 Bytes */ +typedef struct +{ + /* 2-tap delay line for previous sgn values */ + reg32_t m_poleAdaptDelayLine; + /* 2 pole filter coeffs */ + int32_t m_poleCoeff[2]; +} PoleCoeff_data; + +/* Struct required for the zerocoeffcalculator function of bt-aptX encoder and decoder*/ +/* Size of structure: 100 Bytes */ +typedef struct +{ + /* The zero filter length for this subband */ + int32_t m_numZeros; + /* Maximum number of zeros for any subband is 24. */ + /* 24 zero filter coeffs */ + int32_t m_zeroCoeff[24]; +} ZeroCoeff_data; + +/* Struct required for the prediction filtering function of bt-aptX encoder and decoder*/ +/* Size of structure: 200+20=220 Bytes */ +typedef struct +{ + /* Number of zeros associated with this subband */ + int32_t m_numZeros; + /* Zero data delay line (circular) */ + circularBuffer m_zeroDelayLine; + /* 2-tap pole data delay line */ + int32_t m_poleDelayLine[2]; + /* Output from zero filter */ + int32_t m_zeroVal; + /* Output from overall ARMA filter */ + int32_t m_predVal; +} Predictor_data; + +/* Struct required for the Quantisation function of bt-aptX encoder and decoder*/ +/* Size of structure: 24 Bytes */ +typedef struct +{ + /* Number of bits in the quantised code for this subband */ + int32_t codeBits; + /* Pointer to threshold table */ + const int32_t* thresholdTablePtr; + const int32_t* thresholdTablePtr_sl1; + /* Pointer to dither table */ + const int32_t* ditherTablePtr; + /* Pointer to minus Lambda table */ + const int32_t* minusLambdaDTable; + /* Output quantised code */ + int32_t qCode; + /* Alternative quantised code for sync purposes */ + int32_t altQcode; + /* Penalty associated with choosing alternative code */ + int32_t distPenalty; +} Quantiser_data; + +/* Struct required for the inverse Quantisation function of bt-aptX encoder and decoder*/ +/* Size of structure: 32 Bytes */ +typedef struct +{ + /* Pointer to threshold table */ + const int32_t* thresholdTablePtr; + const int32_t* thresholdTablePtr_sl1; + /* Pointer to dither table */ + const int32_t* ditherTablePtr_sf1; + /* Pointer to increment table */ + const int32_t* incrTablePtr; + /* Upper and lower bounds for logDelta */ + int32_t maxLogDelta; + int32_t minLogDelta; + /* Delta (quantisation step size */ + int32_t delta; + /* Delta, expressed as a log base 2 */ + uint16_t logDelta; + /* Output dequantised signal */ + int32_t invQ; + /* pointer to IQuant_tableLogT */ + const int32_t* iquantTableLogPtr; +} IQuantiser_data; + +/* Subband data structure bt-aptX encoder*/ +/* Size of structure: 116+220+32= 368 Bytes */ +typedef struct +{ + /* Subband processing consists of inverse quantisation, predictor + * coefficient update, and predictor filtering. */ + ZeroCoeff_data m_ZeroCoeffData; + PoleCoeff_data m_PoleCoeffData; + /* structure holding the data associated with the predictor */ + Predictor_data m_predData; + /* iqdata holds the data associated with the instance of inverse quantiser */ + IQuantiser_data m_iqdata; +} Subband_data; + +/* Encoder data structure bt-aptX encoder*/ +/* Size of structure: 368*4+24+4*24 = 1592 Bytes */ +typedef struct +{ + /* Subband processing consists of inverse quantisation, predictor + * coefficient update, and predictor filtering. */ + Subband_data m_SubbandData[4]; + int32_t m_codewordHistory; + int32_t m_dithSyncRandBit; + int32_t m_ditherOutputs[4]; + /* structure holding data values for this quantiser */ + Quantiser_data m_qdata[4]; +} Encoder_data; + +/* Number of predictor pole filter coefficients is fixed at 2 for all subbands */ +static const uint32_t numPoleFilterCoeffs = 2; + +/* Subband-specific number of predictor zero filter coefficients. */ +static const uint32_t numZeroFilterCoeffs[4] = {24, 12, 6, 12}; + +/* Delta is scaled by 4 positions within the quantiser and inverse quantiser. */ +static const uint32_t deltaScale = 4; + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //APTXPARAMETERS_H diff --git a/system/embdrv/encoder_for_aptx/src/AptxTables.h b/system/embdrv/encoder_for_aptx/src/AptxTables.h new file mode 100644 index 00000000000..e357b50e664 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/AptxTables.h @@ -0,0 +1,424 @@ +/*------------------------------------------------------------------------------ + * + * All table definitions used for the quantizer. + * + *----------------------------------------------------------------------------*/ + +#ifndef APTXTABLES_H +#define APTXTABLES_H + + +#include "AptxParameters.h" + + +/* Quantisation threshold, logDelta increment and dither tables for 2-bit codes */ +static const int32_t dq2bit16_sl1[3] = +{ + -194080, + 194080, + 890562, +}; + +static const int32_t q2incr16[3] = +{ + 0, + -33, + 136, +}; + +static const int32_t dq2dith16_sf1[3] = +{ + 194080, + 194080, + 502402, +}; + +static const int32_t dq2mLamb16[2] = +{ + 0, + -77081, +}; + +/* Quantisation threshold, logDelta increment and dither tables for 3-bit codes */ +static const int32_t dq3bit16_sl1[5] = +{ + -163006, + 163006, + 542708, + 1120554, + 2669238, +}; + +static const int32_t q3incr16[5] = +{ + 0, + -8, + 33, + 95, + 262, +}; + +static const int32_t dq3dith16_sf1[5] = +{ + 163006, + 163006, + 216698, + 361148, + 1187538, +}; + +static const int32_t dq3mLamb16[4] = +{ + 0, + -13423, + -36113, + -206598, +}; + +/* Quantisation threshold, logDelta increment and dither tables for 4-bit codes */ +static const int32_t dq4bit16_sl1[9] = +{ + -89806, + 89806, + 278502, + 494338, + 759442, + 1113112, + 1652322, + 2720256, + 5190186, +}; + +static const int32_t q4incr16[9] = +{ + 0, + -14, + 6, + 29, + 58, + 96, + 154, + 270, + 521, +}; + +static const int32_t dq4dith16_sf1[9] = +{ + 89806, + 89806, + 98890, + 116946, + 148158, + 205512, + 333698, + 734236, + 1735696, +}; + +static const int32_t dq4mLamb16[8] = +{ + 0, + -2271, + -4514, + -7803, + -14339, + -32047, + -100135, + -250365, +}; + +/* Quantisation threshold, logDelta increment and dither tables for 7-bit codes */ +static const int32_t dq7bit16_sl1[65] = +{ + -9948, + 9948, + 29860, + 49808, + 69822, + 89926, + 110144, + 130502, + 151026, + 171738, + 192666, + 213832, + 235264, + 256982, + 279014, + 301384, + 324118, + 347244, + 370790, + 394782, + 419250, + 444226, + 469742, + 495832, + 522536, + 549890, + 577936, + 606720, + 636290, + 666700, + 698006, + 730270, + 763562, + 797958, + 833538, + 870398, + 908640, + 948376, + 989740, + 1032874, + 1077948, + 1125150, + 1174700, + 1226850, + 1281900, + 1340196, + 1402156, + 1468282, + 1539182, + 1615610, + 1698514, + 1789098, + 1888944, + 2000168, + 2125700, + 2269750, + 2438670, + 2642660, + 2899462, + 3243240, + 3746078, + 4535138, + 5664098, + 7102424, + 8897462, +}; + +static const int32_t q7incr16[65] = +{ + 0, + -21, + -19, + -17, + -15, + -12, + -10, + -8, + -6, + -4, + -1, + 1, + 3, + 6, + 8, + 10, + 13, + 15, + 18, + 20, + 23, + 26, + 29, + 31, + 34, + 37, + 40, + 43, + 47, + 50, + 53, + 57, + 60, + 64, + 68, + 72, + 76, + 80, + 85, + 89, + 94, + 99, + 105, + 110, + 116, + 123, + 129, + 136, + 144, + 152, + 161, + 171, + 182, + 194, + 207, + 223, + 241, + 263, + 291, + 328, + 382, + 467, + 522, + 522, + 522, +}; + +static const int32_t dq7dith16_sf1[65] = +{ + 9948, + 9948, + 9962, + 9988, + 10026, + 10078, + 10142, + 10218, + 10306, + 10408, + 10520, + 10646, + 10784, + 10934, + 11098, + 11274, + 11462, + 11664, + 11880, + 12112, + 12358, + 12618, + 12898, + 13194, + 13510, + 13844, + 14202, + 14582, + 14988, + 15422, + 15884, + 16380, + 16912, + 17484, + 18098, + 18762, + 19480, + 20258, + 21106, + 22030, + 23044, + 24158, + 25390, + 26760, + 28290, + 30008, + 31954, + 34172, + 36728, + 39700, + 43202, + 47382, + 52462, + 58762, + 66770, + 77280, + 91642, + 112348, + 144452, + 199326, + 303512, + 485546, + 643414, + 794914, + 1000124, +}; + +static const int32_t dq7mLamb16[65] = +{ + 0, + -4, + -7, + -10, + -13, + -16, + -19, + -22, + -26, + -28, + -32, + -35, + -38, + -41, + -44, + -47, + -51, + -54, + -58, + -62, + -65, + -70, + -74, + -79, + -84, + -90, + -95, + -102, + -109, + -116, + -124, + -133, + -143, + -154, + -166, + -180, + -195, + -212, + -231, + -254, + -279, + -308, + -343, + -383, + -430, + -487, + -555, + -639, + -743, + -876, + -1045, + -1270, + -1575, + -2002, + -2628, + -3591, + -5177, + -8026, + -13719, + -26047, + -45509, + -39467, + -37875, + -51303, + 0, +}; + +/* Array of structures containing subband parameters. */ +static const SubbandParameters subbandParameters[NUMSUBBANDS] = +{ + /* LL band */ + { 0, dq7bit16_sl1, 0, dq7dith16_sf1, dq7mLamb16, q7incr16, 7, (18*256)-1, -20, 24 }, + + /* LH band */ + { 0, dq4bit16_sl1, 0, dq4dith16_sf1, dq4mLamb16, q4incr16, 4, (21*256)-1, -23, 12 }, + + /* HL band */ + { 0, dq2bit16_sl1, 0, dq2dith16_sf1, dq2mLamb16, q2incr16, 2, (23*256)-1, -25, 6 }, + + /* HH band */ + { 0, dq3bit16_sl1, 0, dq3dith16_sf1, dq3mLamb16, q3incr16, 3, (22*256)-1, -24, 12 } +}; + + +#endif //APTXTABLES_H diff --git a/system/embdrv/encoder_for_aptx/src/CBStruct.h b/system/embdrv/encoder_for_aptx/src/CBStruct.h new file mode 100644 index 00000000000..b3d77cfebb5 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/CBStruct.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------------ + * + * Structure required to implement a circular buffer. + * + *----------------------------------------------------------------------------*/ + +#ifndef CBSTRUCT_H +#define CBSTRUCT_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +typedef struct circularBuffer_t +{ + /* Buffer storage */ + int32_t buffer[48]; + /* Pointer to current buffer location */ + uint32_t pointer; + /* Modulo length of circular buffer */ + uint32_t modulo; +}circularBuffer; + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //CBSTRUCT_H \ No newline at end of file diff --git a/system/embdrv/encoder_for_aptx/src/CodewordPacker.h b/system/embdrv/encoder_for_aptx/src/CodewordPacker.h new file mode 100644 index 00000000000..688245b3213 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/CodewordPacker.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------------ + * + * Prototype declaration of the CodewordPacker Function + * + * This functions allows a client to supply an array of 4 quantised codes + * (1 per subband) and obtain a packed version as a 16-bit aptX codeword. + * + *----------------------------------------------------------------------------*/ + +#ifndef CODEWORDPACKER_H +#define CODEWORDPACKER_H + + +#include "AptxParameters.h" + + +XBT_INLINE_ int32_t packCodeword(Encoder_data* EncoderDataPt, uint32_t aligned) +{ + int32_t syncContribution; + int32_t hhCode; + int32_t codeword; + + /* The per-channel contribution to derive the current sync bit is the XOR of + * the 4 code lsbs and the random dither bit. The SyncInserter engineers it + * such that the XOR of the sync contributions from the left and right + * channel give the actual sync bit value. The per-channel sync bit + * contribution overwrites the HH code lsb in the packed codeword. */ + if (aligned != no_sync) + { + syncContribution = + (EncoderDataPt->m_qdata[0].qCode ^ + EncoderDataPt->m_qdata[1].qCode ^ + EncoderDataPt->m_qdata[2].qCode ^ + EncoderDataPt->m_qdata[3].qCode ^ + EncoderDataPt->m_dithSyncRandBit) & 0x1; + hhCode = (EncoderDataPt->m_qdata[HH].qCode & 0x6) | syncContribution; + + /* Pack the 16-bit codeword with the appropriate number of lsbs from each + * quantised code (LL=7, LH=4, HL=2, HH=3). */ + codeword = + (EncoderDataPt->m_qdata[LL].qCode & 0x7fL) | + ((EncoderDataPt->m_qdata[LH].qCode & 0xfL) << 7) | + ((EncoderDataPt->m_qdata[HL].qCode & 0x3L) << 11) | + (hhCode << 13); + } + else + { // don't add sync contribution for non-autosync mode + codeword = + (EncoderDataPt->m_qdata[LL].qCode & 0x7fL) | + ((EncoderDataPt->m_qdata[LH].qCode & 0xfL) << 7) | + ((EncoderDataPt->m_qdata[HL].qCode & 0x3L) << 11) | + ((EncoderDataPt->m_qdata[HH].qCode & 0x7L) << 13); + + } + return codeword; +} + + +#endif //CODEWORDPACKER_H diff --git a/system/embdrv/encoder_for_aptx/src/DitherGenerator.h b/system/embdrv/encoder_for_aptx/src/DitherGenerator.h new file mode 100644 index 00000000000..9b4c686f8a5 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/DitherGenerator.h @@ -0,0 +1,102 @@ +/*------------------------------------------------------------------------------ + * + * These functions allow clients to update an internal codeword history + * attribute from previously-generated quantised codes, and to generate a new + * pseudo-random dither value per subband from this internal attribute. + * + *----------------------------------------------------------------------------*/ + +#ifndef DITHERGENERATOR_H +#define DITHERGENERATOR_H + + +#include "AptxParameters.h" + + +/* This function updates an internal bit-pool (private + * variable in DitherGenerator) based on bits obtained from + * previously encoded or received aptX codewords. */ +XBT_INLINE_ int32_t xbtEncupdateCodewordHistory(int32_t quantisedCodes[4], int32_t m_codewordHistory) +{ + int32_t newBits; + int32_t updatedCodewordHistory; + + const int32_t llMask = 0x3L; + const int32_t lhMask = 0x2L; + const int32_t hlMask = 0x1L; + const uint32_t lhShift = 1; + const uint32_t hlShift = 3; + /* Shift value to left-justify a 24-bit value in a 32-bit signed variable*/ + const uint32_t leftJustifyShift = 8; + const uint32_t numNewBits = 4; + + /* Make a 4-bit vector from particular bits from 3 quantised codes */ + newBits = (quantisedCodes[LL] & llMask) + + ((quantisedCodes[LH] & lhMask) << lhShift) + + ((quantisedCodes[HL] & hlMask) << hlShift); + + /* Add the 4 new bits to the codeword history. Note that this is a 24-bit + * value LEFT-JUSTIFIED in a 32-bit signed variable. Maintaining the history + * as signed is useful in the dither generation process below. */ + updatedCodewordHistory = + (m_codewordHistory << numNewBits) + (newBits << leftJustifyShift); + + return updatedCodewordHistory; +} + +/* Function to generate a dither value for each subband based + * on the current contents of the codewordHistory bit-pool. */ +XBT_INLINE_ int32_t xbtEncgenerateDither(int32_t m_codewordHistory, int32_t* m_ditherOutputs) +{ + int32_t history24b; + int32_t upperAcc, lowerAcc; + int32_t accSum; + int64_t tmp_acc; + int32_t ditherSample; + int32_t m_dithSyncRandBit; + + /* Fixed value to multiply codeword history variable by */ + const uint32_t dithConstMultiplier = 0x4f1bbbL; + /* Shift value to left-justify a 24-bit value in a 32-bit signed variable*/ + const uint32_t leftJustifyShift = 8; + + /* AND mask to retain only the lower 24 bits of a variable */ + const int32_t keepLower24bitsMask = 0xffffffL; + + /* Convert the codeword history to a 24-bit signed value. This can be done + * cheaply with a 8-position right-shift since it is maintained as 24-bits + * value left-justified in a signed 32-bit variable. */ + history24b = m_codewordHistory >> (leftJustifyShift - 1); + + /* Multiply the history by a fixed constant. The constant has already been + * shifted right by 1 position to compensate for the left-shift introduced + * on the product by the fractional multiplier. */ + tmp_acc = ((int64_t)history24b * (int64_t)dithConstMultiplier); + + /* Get the upper and lower 24-bit values from the accumulator, and form + * their sum. */ + upperAcc = ((int32_t)(tmp_acc >> 24)) & 0x00FFFFFFL; + lowerAcc = ((int32_t)tmp_acc) & 0x00FFFFFFL; + accSum = upperAcc + lowerAcc; + + /* The dither sample is the 2 msbs of lowerAcc and the 22 lsbs of accSum */ + ditherSample = ((lowerAcc >> 22) + (accSum << 2)) & keepLower24bitsMask; + + /* The sign bit of 24-bit accSum is saved as a random bit to + * assist in the aptX sync insertion process. */ + m_dithSyncRandBit = (accSum >> 23) & 0x1; + + /* Successive dither outputs for the 4 subbands are versions of ditherSample + * offset by a further 5-position left shift for each subband. Also apply a + * constant left-shift of 8 to turn the values into signed 24-bit values + * left-justified in the 32-bit ditherOutput variable. */ + m_ditherOutputs[HH] = ditherSample << leftJustifyShift; + m_ditherOutputs[HL] = ditherSample << (5 + leftJustifyShift); + m_ditherOutputs[LH] = ditherSample << (10 + leftJustifyShift); + m_ditherOutputs[LL] = ditherSample << (15 + leftJustifyShift); + + return m_dithSyncRandBit; +}; + + +#endif //DITHERGENERATOR_H diff --git a/system/embdrv/encoder_for_aptx/src/ProcessSubband.c b/system/embdrv/encoder_for_aptx/src/ProcessSubband.c new file mode 100644 index 00000000000..0dfbb4fa8cb --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/ProcessSubband.c @@ -0,0 +1,43 @@ +#include "AptxParameters.h" +#include "SubbandFunctionsCommon.h" +#include "SubbandFunctions.h" + + +/* This function carries out all subband processing (common to both encode and decode). */ +void processSubband(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt) +{ + /* Inverse quantisation */ + invertQuantisation(qCode, ditherVal, iqDataPt); + + /* Predictor pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, SubbandDataPt->m_predData.m_zeroVal, &SubbandDataPt->m_PoleCoeffData); + + /* Predictor filtering */ + performPredictionFiltering(iqDataPt->invQ, SubbandDataPt); +} + +/* processSubbandLL is used for the LL subband only. */ +void processSubbandLL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt) +{ + /* Inverse quantisation */ + invertQuantisation(qCode, ditherVal, iqDataPt); + + /* Predictor pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, SubbandDataPt->m_predData.m_zeroVal, &SubbandDataPt->m_PoleCoeffData); + + /* Predictor filtering */ + performPredictionFilteringLL(iqDataPt->invQ, SubbandDataPt); +} + +/* processSubbandHL is used for the HL subband only. */ +void processSubbandHL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt) +{ + /* Inverse quantisation */ + invertQuantisationHL(qCode, ditherVal, iqDataPt); + + /* Predictor pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, SubbandDataPt->m_predData.m_zeroVal, &SubbandDataPt->m_PoleCoeffData); + + /* Predictor filtering */ + performPredictionFilteringHL(iqDataPt->invQ, SubbandDataPt); +} diff --git a/system/embdrv/encoder_for_aptx/src/Qmf.h b/system/embdrv/encoder_for_aptx/src/Qmf.h new file mode 100644 index 00000000000..acc6696b747 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/Qmf.h @@ -0,0 +1,142 @@ +/*------------------------------------------------------------------------------ + * + * This file includes the coefficient tables or the two convolution function + * It also includes the definition of Qmf_storage and the prototype of all + * necessary functions required to implement the QMF filtering. + * + *----------------------------------------------------------------------------*/ + +#ifndef QMF_H +#define QMF_H + + +#include "AptxParameters.h" + + +typedef struct +{ + int16_t QmfL_buf[32]; + int16_t QmfH_buf[32]; + int32_t QmfLH_buf[32]; + int32_t QmfHL_buf[32]; + int32_t QmfLL_buf[32]; + int32_t QmfHH_buf[32]; + int32_t QmfI_pt; + int32_t QmfO_pt; +}Qmf_storage; + +/* Outer QMF filter for Enhanced aptX is a symmetrical 32-tap filter (16 + * different coefficients). The table in defined in QmfConv.c */ +#ifndef _STDQMFOUTERCOEFF +const int32_t Qmf_outerCoeffs[12] = +{ + /* (C(1/30)C(3/28)), C(5/26), C(7/24) */ + 0xFE6302DA, 0xFFFFDA75, 0x0000AA6A, + /* C(9/22), C(11/20), C(13/18), C(15/16) */ + 0xFFFE273E, 0x00041E95, 0xFFF710B5, 0x002AC12E, + /* C(17/14), C(19/12), (C(21/10)C(23/8)) */ + 0x000AA328, 0xFFFD8D1F, 0x211E6BDB, + /* (C(25/6)C(27/4)), (C(29/2)C(31/0)) */ + 0x0DB7D8C5, 0xFC7F02B0 +}; +#else +const int32_t Qmf_outerCoeffs[16] = +{ + 730, -413, -9611, 43626, + -121026, 269973, -585547, 2801966, + 697128, -160481, 27611, 8478, + -10043, 3511, 688, -897 +}; +#endif + +/* Each inner QMF filter for Enhanced aptX is a symmetrical 32-tap filter (16 + * different coefficients) */ +const int32_t Qmf_innerCoeffs[16] = +{ + 1033, -584, -13592, 61697, + -171156, 381799, -828088, 3962579, + 985888, -226954, 39048, 11990, + -14203, 4966, 973, -1268 +}; + +void AsmQmfConvI (const int32_t *p1dl_buffPtr, const int32_t *p2dl_buffPtr, const int32_t *coeffPtr, int32_t* filterOutputs); +void AsmQmfConvO (const int16_t *p1dl_buffPtr, const int16_t *p2dl_buffPtr, const int32_t *coeffPtr, int32_t* convSumDiff); + +XBT_INLINE_ void QmfAnalysisFilter(int32_t pcm[4], Qmf_storage* Qmf_St, int32_t* predVals, int32_t* aqmfOutputs) +{ + int32_t convSumDiff[4]; + int32_t filterOutputs[4]; + + int32_t lc_QmfO_pt = (Qmf_St->QmfO_pt); + int32_t lc_QmfI_pt = (Qmf_St->QmfI_pt); + + /* Symbolic constants to represent the first and second set out outer filter + * outputs. */ + enum { FirstOuterOutputs = 0, SecondOuterOutputs = 1 }; + + /* Load outer filter phase1 and phase2 delay lines with the first 2 PCM + * samples. Convolve the filter and get the 2 convolution results. */ + Qmf_St->QmfL_buf[lc_QmfO_pt + 16] = (int16_t)pcm[FirstPcm]; + Qmf_St->QmfL_buf[lc_QmfO_pt] = (int16_t)pcm[FirstPcm]; + Qmf_St->QmfH_buf[lc_QmfO_pt + 16] = (int16_t)pcm[SecondPcm]; + Qmf_St->QmfH_buf[lc_QmfO_pt++] = (int16_t)pcm[SecondPcm]; + lc_QmfO_pt &= 0xF; + + AsmQmfConvO(&Qmf_St->QmfL_buf[lc_QmfO_pt + 15], &Qmf_St->QmfH_buf[lc_QmfO_pt], Qmf_outerCoeffs, &convSumDiff[0]); + + + /* Load outer filter phase1 and phase2 delay lines with the second 2 PCM + * samples. Convolve the filter and get the 2 convolution results. */ + Qmf_St->QmfL_buf[lc_QmfO_pt + 16] = (int16_t)pcm[ThirdPcm]; + Qmf_St->QmfL_buf[lc_QmfO_pt] = (int16_t)pcm[ThirdPcm]; + Qmf_St->QmfH_buf[lc_QmfO_pt + 16] = (int16_t)pcm[FourthPcm]; + Qmf_St->QmfH_buf[lc_QmfO_pt++] = (int16_t)pcm[FourthPcm]; + lc_QmfO_pt &= 0xF; + + AsmQmfConvO(&Qmf_St->QmfL_buf[lc_QmfO_pt + 15], &Qmf_St->QmfH_buf[lc_QmfO_pt], Qmf_outerCoeffs, &convSumDiff[1]); + + /* Load the first inner filter phase1 and phase2 delay lines with the 2 + * convolution sum (low-pass) outer filter outputs. Convolve the filter and + * get the 2 convolution results. The first 2 analysis filter outputs are + * the sum and difference values for the first inner filter convolutions. */ + Qmf_St->QmfLL_buf[lc_QmfI_pt + 16] = convSumDiff[0]; + Qmf_St->QmfLL_buf[lc_QmfI_pt] = convSumDiff[0]; + Qmf_St->QmfLH_buf[lc_QmfI_pt + 16] = convSumDiff[1]; + Qmf_St->QmfLH_buf[lc_QmfI_pt] = convSumDiff[1]; + + AsmQmfConvI(&Qmf_St->QmfLL_buf[lc_QmfI_pt + 16], &Qmf_St->QmfLH_buf[lc_QmfI_pt + 1],&Qmf_innerCoeffs[0], &filterOutputs[LL]); + + /* Load the second inner filter phase1 and phase2 delay lines with the 2 + * convolution difference (high-pass) outer filter outputs. Convolve the + * filter and get the 2 convolution results. The second 2 analysis filter + * outputs are the sum and difference values for the second inner filter + * convolutions. */ + Qmf_St->QmfHL_buf[lc_QmfI_pt + 16] = convSumDiff[2]; + Qmf_St->QmfHL_buf[lc_QmfI_pt] = convSumDiff[2]; + Qmf_St->QmfHH_buf[lc_QmfI_pt + 16] = convSumDiff[3]; + Qmf_St->QmfHH_buf[lc_QmfI_pt++] = convSumDiff[3]; + lc_QmfI_pt &= 0xF; + + AsmQmfConvI(&Qmf_St->QmfHL_buf[lc_QmfI_pt + 15], &Qmf_St->QmfHH_buf[lc_QmfI_pt],&Qmf_innerCoeffs[0], &filterOutputs[HL]); + + /* Subtracted the previous predicted value from the filter output on a + * per-subband basis. Ensure these values are saturated, if necessary. + * Manual unrolling */ + aqmfOutputs[LL] = filterOutputs[LL] - predVals[LL]; + aqmfOutputs[LL] = ssat24(aqmfOutputs[LL]); + + aqmfOutputs[LH] = filterOutputs[LH] - predVals[LH]; + aqmfOutputs[LH] = ssat24(aqmfOutputs[LH]); + + aqmfOutputs[HL] = filterOutputs[HL] - predVals[HL]; + aqmfOutputs[HL] = ssat24(aqmfOutputs[HL]); + + aqmfOutputs[HH] = filterOutputs[HH] - predVals[HH]; + aqmfOutputs[HH] = ssat24(aqmfOutputs[HH]); + + (Qmf_St->QmfO_pt) = lc_QmfO_pt; + (Qmf_St->QmfI_pt) = lc_QmfI_pt; +} + + +#endif //QMF_H diff --git a/system/embdrv/encoder_for_aptx/src/QmfConv.c b/system/embdrv/encoder_for_aptx/src/QmfConv.c new file mode 100644 index 00000000000..14e342ef5ae --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/QmfConv.c @@ -0,0 +1,327 @@ +/*------------------------------------------------------------------------------ + * + * This file includes convolution functions required for the Qmf. + * + *----------------------------------------------------------------------------*/ + + +#include "AptxParameters.h" + + +void AsmQmfConvO(const int16_t* p1dl_buffPtr, const int16_t* p2dl_buffPtr, const int32_t* coeffPtr, int32_t* convSumDiff) +{ + /* Since all manipulated data are "int16_t" it is possible to + * reduce the number of loads by using int32_t type and manipulating + * pairs of data + */ + int32_t acc; + // Manual inlining as IAR compiler does not seem to do it itself... + // WARNING: This inlining assumes that m_qmfDelayLineLength == 16 + int32_t tmp_round0; + int64_t local_acc0; + int64_t local_acc1; + int32_t coeffVal0; + int32_t coeffVal1; + int16_t data0; + int16_t data1; + int16_t data2; + int16_t data3; + int32_t phaseConv[2]; + int32_t convSum; + int32_t convDiff; + + coeffVal0 = (*(coeffPtr)); + coeffVal1 = (*(coeffPtr + 1)); + data0 = (*(p1dl_buffPtr)); + data1 = (*(p2dl_buffPtr)); + data2 = (*(p1dl_buffPtr - 1)); + data3 = (*(p2dl_buffPtr + 1)); + + local_acc0 = ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 = ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 2)); + coeffVal1 = (*(coeffPtr + 3)); + data0 = (*(p1dl_buffPtr - 2)); + data1 = (*(p2dl_buffPtr + 2)); + data2 = (*(p1dl_buffPtr - 3)); + data3 = (*(p2dl_buffPtr + 3)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 4)); + coeffVal1 = (*(coeffPtr + 5)); + data0 = (*(p1dl_buffPtr - 4)); + data1 = (*(p2dl_buffPtr + 4)); + data2 = (*(p1dl_buffPtr - 5)); + data3 = (*(p2dl_buffPtr + 5)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 6)); + coeffVal1 = (*(coeffPtr + 7)); + data0 = (*(p1dl_buffPtr - 6)); + data1 = (*(p2dl_buffPtr + 6)); + data2 = (*(p1dl_buffPtr - 7)); + data3 = (*(p2dl_buffPtr + 7)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 8)); + coeffVal1 = (*(coeffPtr + 9)); + data0 = (*(p1dl_buffPtr - 8)); + data1 = (*(p2dl_buffPtr + 8)); + data2 = (*(p1dl_buffPtr - 9)); + data3 = (*(p2dl_buffPtr + 9)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 10)); + coeffVal1 = (*(coeffPtr + 11)); + data0 = (*(p1dl_buffPtr - 10)); + data1 = (*(p2dl_buffPtr + 10)); + data2 = (*(p1dl_buffPtr - 11)); + data3 = (*(p2dl_buffPtr + 11)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 12)); + coeffVal1 = (*(coeffPtr + 13)); + data0 = (*(p1dl_buffPtr - 12)); + data1 = (*(p2dl_buffPtr + 12)); + data2 = (*(p1dl_buffPtr - 13)); + data3 = (*(p2dl_buffPtr + 13)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 14)); + coeffVal1 = (*(coeffPtr + 15)); + data0 = (*(p1dl_buffPtr - 14)); + data1 = (*(p2dl_buffPtr + 14)); + data2 = (*(p1dl_buffPtr - 15)); + data3 = (*(p2dl_buffPtr + 15)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + tmp_round0 = (int32_t)local_acc0 & 0x00FFFFL; + + local_acc0 += 0x004000L; + acc = (int32_t)(local_acc0 >> 15); + if (tmp_round0 == 0x004000L) + acc--; + if (acc > 8388607) + acc = 8388607; + if (acc < -8388608) + acc = -8388608; + + phaseConv[0] = (int32_t)acc; + + tmp_round0 = (int32_t)local_acc1 & 0x00FFFFL; + + local_acc1 += 0x004000L; + acc = (int32_t)(local_acc1 >> 15); + if (tmp_round0 == 0x004000L) + acc--; + if (acc > 8388607) + acc = 8388607; + if (acc < -8388608) + acc = -8388608; + + phaseConv[1] = (int32_t)acc; + + convSum = phaseConv[1] + phaseConv[0]; + if (convSum > 8388607) + convSum = 8388607; + if (convSum < -8388608) + convSum = -8388608; + + convDiff = phaseConv[1] - phaseConv[0]; + if (convDiff > 8388607) + convDiff = 8388607; + if (convDiff < -8388608) + convDiff = -8388608; + + *(convSumDiff) = convSum; + *(convSumDiff + 2) = convDiff; +} + +void AsmQmfConvI(const int32_t* p1dl_buffPtr, const int32_t* p2dl_buffPtr, const int32_t* coeffPtr, int32_t* filterOutputs) +{ + int32_t acc; + // WARNING: This inlining assumes that m_qmfDelayLineLength == 16 + int32_t tmp_round0; + int64_t local_acc0; + int64_t local_acc1; + int32_t coeffVal0; + int32_t coeffVal1; + int32_t data0; + int32_t data1; + int32_t data2; + int32_t data3; + int32_t phaseConv[2]; + int32_t convSum; + int32_t convDiff; + + coeffVal0 = (*(coeffPtr)); + coeffVal1 = (*(coeffPtr + 1)); + data0 = (*(p1dl_buffPtr)); + data1 = (*(p2dl_buffPtr)); + data2 = (*(p1dl_buffPtr - 1)); + data3 = (*(p2dl_buffPtr + 1)); + + local_acc0 = ((int64_t)(coeffVal0)*data0); + local_acc1 = ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 2)); + coeffVal1 = (*(coeffPtr + 3)); + data0 = (*(p1dl_buffPtr - 2)); + data1 = (*(p2dl_buffPtr + 2)); + data2 = (*(p1dl_buffPtr - 3)); + data3 = (*(p2dl_buffPtr + 3)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 4)); + coeffVal1 = (*(coeffPtr + 5)); + data0 = (*(p1dl_buffPtr - 4)); + data1 = (*(p2dl_buffPtr + 4)); + data2 = (*(p1dl_buffPtr - 5)); + data3 = (*(p2dl_buffPtr + 5)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 6)); + coeffVal1 = (*(coeffPtr + 7)); + data0 = (*(p1dl_buffPtr - 6)); + data1 = (*(p2dl_buffPtr + 6)); + data2 = (*(p1dl_buffPtr - 7)); + data3 = (*(p2dl_buffPtr + 7)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 8)); + coeffVal1 = (*(coeffPtr + 9)); + data0 = (*(p1dl_buffPtr - 8)); + data1 = (*(p2dl_buffPtr + 8)); + data2 = (*(p1dl_buffPtr - 9)); + data3 = (*(p2dl_buffPtr + 9)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 10)); + coeffVal1 = (*(coeffPtr + 11)); + data0 = (*(p1dl_buffPtr - 10)); + data1 = (*(p2dl_buffPtr + 10)); + data2 = (*(p1dl_buffPtr - 11)); + data3 = (*(p2dl_buffPtr + 11)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 12)); + coeffVal1 = (*(coeffPtr + 13)); + data0 = (*(p1dl_buffPtr - 12)); + data1 = (*(p2dl_buffPtr + 12)); + data2 = (*(p1dl_buffPtr - 13)); + data3 = (*(p2dl_buffPtr + 13)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 14)); + coeffVal1 = (*(coeffPtr + 15)); + data0 = (*(p1dl_buffPtr - 14)); + data1 = (*(p2dl_buffPtr + 14)); + data2 = (*(p1dl_buffPtr - 15)); + data3 = (*(p2dl_buffPtr + 15)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + tmp_round0 = (int32_t)local_acc0; + + local_acc0 += 0x00400000L; + acc = (int32_t)(local_acc0 >> 23); + + if ((((tmp_round0 << 8) ^ 0x40000000) == 0)) + { + acc--; + } + + if (acc > 8388607) + acc = 8388607; + if (acc < -8388608) + acc = -8388608; + + phaseConv[0] = (int32_t)acc; + tmp_round0 = (int32_t)local_acc1; + + local_acc1 += 0x00400000L; + acc = (int32_t)(local_acc1 >> 23); + if ((((tmp_round0 << 8) ^ 0x40000000) == 0)) + { + acc--; + } + + if (acc > 8388607) + acc = 8388607; + if (acc < -8388608) + acc = -8388608; + + phaseConv[1] = (int32_t)acc; + + convSum = phaseConv[1] + phaseConv[0]; + if (convSum > 8388607) convSum = 8388607; + if (convSum < -8388608) convSum = -8388608; + + *(filterOutputs) = convSum; + + convDiff = phaseConv[1] - phaseConv[0]; + if (convDiff > 8388607) convDiff = 8388607; + if (convDiff < -8388608) convDiff = -8388608; + + *(filterOutputs + 1) = convDiff; +} diff --git a/system/embdrv/encoder_for_aptx/src/QuantiseDifference.c b/system/embdrv/encoder_for_aptx/src/QuantiseDifference.c new file mode 100644 index 00000000000..17e412d230f --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/QuantiseDifference.c @@ -0,0 +1,711 @@ +#include "AptxParameters.h" +#include "Quantiser.h" +#include "AptxTables.h" + + +XBT_INLINE_ int32_t BsearchLL(const int32_t absDiffSignalShifted, const int32_t delta, const int32_t* dqbitTablePrt) +{ + int32_t qCode; + reg64_t tmp_acc; + int32_t tmp; + int32_t lc_delta = delta << 8; + + qCode = 0; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[32]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode = 32; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 16]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 16; + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 8]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 8; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 4]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 4; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 2]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 2; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 1]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode++; + + return (qCode); +} + +XBT_INLINE_ int32_t BsearchHL(const int32_t absDiffSignalShifted, const int32_t delta) +{ + reg64_t tmp_acc; + int32_t lc_delta = delta << 8; + + /* first iteration */ + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)(97040 << 1); + tmp_acc.s32.h -= absDiffSignalShifted; + if (tmp_acc.s64 <= 0) + return (1); + else + return (0); +} + +XBT_INLINE_ int32_t BsearchHH(const int32_t absDiffSignalShifted, const int32_t delta, const int32_t* dqbitTablePrt) +{ + int32_t qCode; + reg64_t tmp_acc; + int32_t tmp; + int32_t lc_delta = delta << 8; + qCode = 0; + + /* first iteration */ + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[2]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 2; + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 1]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode++; + + return (qCode); +} + +XBT_INLINE_ int32_t BsearchLH(const int32_t absDiffSignalShifted, const int32_t delta, const int32_t* dqbitTablePrt) +{ + int32_t qCode; + reg64_t tmp_acc; + int32_t tmp; + int32_t lc_delta = delta << 8; + + /* first iteration */ + qCode = 0; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[4]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode = 4; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 2]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 2; + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 1]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode++; + + return (qCode); +} + +void quantiseDifferenceHL(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt) +{ + int32_t absDiffSignal; + int32_t absDiffSignalShifted; + int32_t index; + int32_t dithSquared; + int32_t minusLambdaD; + int32_t acc; + int32_t threshDiff; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL; + int32_t tmp_qCode; + int32_t tmp_altQcode; + uint32_t tmp_round0; + int32_t _delta; + + /* Form the absolute value of the difference signal and maintain a version + * that is right-shifted 4 places for delta scaling. */ + absDiffSignal = -diffSignal; + if (diffSignal >= 0) absDiffSignal = diffSignal; + absDiffSignal = ssat24(absDiffSignal); + absDiffSignalShifted = absDiffSignal >> deltaScale; + absDiffSignalShifted = ssat24(absDiffSignalShifted); + + /* Binary search for the quantised code. This search terminates with the + * table index of the LARGEST threshold table value for which + * absDiffSignalShifted >= (delta * threshold) + */ + index = BsearchHL(absDiffSignalShifted, delta); + + /* We actually wanted the SMALLEST magnitude quantised code for which + * absDiffSignalShifted < (delta * threshold) + * i.e. the code with the next highest magnitude than the one we actually + * found. We could add +1 to the code magnitude to do this, but we need to + * subtract 1 from the code magnitude to compensate for the "phantom + * element" at the base of the quantisation table. These two effects cancel + * out, so we leave the value of code alone. However, we need to form code+1 + * to get the proper index into the both the threshold and dither tables, + * since we must skip over the phantom element at the base. */ + qdata_pt->qCode = index; + + /* Square the dither and get the value back from the ALU + * (saturated/rounded). */ + tmp_acc.s64 = ((int64_t)ditherVal * (int64_t)ditherVal); + + acc = tmp_acc.s32.h; + + tmp_round0 = (uint32_t)acc << 8; + + acc = (acc >> 6) + 1; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + acc = ssat24(acc); + + dithSquared = acc; + + /* Form the negative difference of the dither values at index and index-1. + * Load the accumulator with this value divided by 2. Ensure saturation is + * applied to the difference calculation. */ + minusLambdaD = qdata_pt->minusLambdaDTable[index]; + + tmp_accL = (1 << 23) - (int32_t)dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = (int32_t)tmp_acc.s32.l << 8; + + acc = (tmp_acc.u32.l >> 22) | (tmp_acc.s32.h << 10); + acc++; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + // worst case value for acc = 0x000d3e08 + // no saturation required + + /* Add the threshold table values at index and index-1 to the accumulated + * value. */ + acc += qdata_pt->thresholdTablePtr_sl1[index + 1] >> 1; + //// worst case value for acc = 0x000d3e08 + 0x43E1DB = 511FE3 + acc += qdata_pt->thresholdTablePtr_sl1[index] >> 1; + //// worst case value for acc = 0x511FE3 + 0x362FEC = 874FCF + + /* Form the threshold table difference at index and index-1. Ensure + * saturation is applied to the difference calculation. */ + threshDiff = qdata_pt->thresholdTablePtr_sl1[index + 1] - qdata_pt->thresholdTablePtr_sl1[index]; + + /* Based on the sign of the difference signal, either add or subtract the + * threshold table difference from the accumulated value. Recover the final + * accumulated value (saturated/rounded) */ + if (diffSignal < 0) + threshDiff = -threshDiff; + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)threshDiff); + + tmp_reg64.s32.h += acc; + acc = tmp_reg64.s32.h; + + if (tmp_reg64.u32.l >= 0x80000000) + acc++; + tmp_round0 = (tmp_reg64.u32.l >> 1) | (tmp_reg64.s32.h << 31); + + acc = ssat24(acc); + + if (tmp_round0 == 0x40000000L) + acc--; + _delta = -delta << 8; + + acc = acc << 4; + + /* Form (absDiffSignal * 0.125) - (acc * delta), which is the final distance + * signal used to determine if dithering alters the quantised code value or + * not. */ + // worst case value for delta is 0x7d400 + tmp_reg64.s64 = ((int64_t)acc * (int64_t)_delta); + tmp_reg64.s32.h += absDiffSignal; + tmp_round0 = (tmp_reg64.u32.l >> 4) | (tmp_reg64.s32.h << 28); + acc = tmp_reg64.s32.h + (1 << 2); + acc >>= 3; + if (tmp_round0 == 0x40000000L) + { + acc--; + } + + tmp_qCode = qdata_pt->qCode; + tmp_altQcode = tmp_qCode - 1; + /* Check the sign of the distance penalty. Get the sign from the + * full-precision accumulator, as done in the Kalimba code. */ + if (tmp_reg64.s32.h < 0) + { + /* The distance is -ve. The optimum code needs decremented by 1 and the + * alternative code is 1 greater than this. Get the rounded version of the + * -ve distance penalty and negate this (form distance magnitude) before + * writing the value out */ + tmp_qCode = tmp_altQcode; + tmp_altQcode++; + acc = -acc; + } + + qdata_pt->distPenalty = acc; + /* If the difference signal is negative, bitwise invert the code (restores + * sign to the magnitude). */ + if (diffSignal < 0) + { + tmp_qCode = ~tmp_qCode; + tmp_altQcode = ~tmp_altQcode; + } + qdata_pt->altQcode = tmp_altQcode; + qdata_pt->qCode = tmp_qCode; +} + +void quantiseDifferenceHH(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt) +{ + int32_t absDiffSignal; + int32_t absDiffSignalShifted; + int32_t index; + int32_t dithSquared; + int32_t minusLambdaD; + int32_t acc; + int32_t threshDiff; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL; + int32_t tmp_qCode; + int32_t tmp_altQcode; + uint32_t tmp_round0; + int32_t _delta; + + /* Form the absolute value of the difference signal and maintain a version + * that is right-shifted 4 places for delta scaling. */ + absDiffSignal = -diffSignal; + if (diffSignal >= 0) absDiffSignal = diffSignal; + absDiffSignal = ssat24(absDiffSignal); + absDiffSignalShifted = absDiffSignal >> deltaScale; + absDiffSignalShifted = ssat24(absDiffSignalShifted); + + /* Binary search for the quantised code. This search terminates with the + * table index of the LARGEST threshold table value for which + * absDiffSignalShifted >= (delta * threshold) + */ + index = BsearchHH(absDiffSignalShifted, delta, qdata_pt->thresholdTablePtr_sl1); + + /* We actually wanted the SMALLEST magnitude quantised code for which + * absDiffSignalShifted < (delta * threshold) + * i.e. the code with the next highest magnitude than the one we actually + * found. We could add +1 to the code magnitude to do this, but we need to + * subtract 1 from the code magnitude to compensate for the "phantom + * element" at the base of the quantisation table. These two effects cancel + * out, so we leave the value of code alone. However, we need to form code+1 + * to get the proper index into the both the threshold and dither tables, + * since we must skip over the phantom element at the base. */ + qdata_pt->qCode = index; + + /* Square the dither and get the value back from the ALU + * (saturated/rounded). */ + tmp_acc.s64 = ((int64_t)ditherVal * (int64_t)ditherVal); + + acc = tmp_acc.s32.h; + + tmp_round0 = (uint32_t)acc << 8; + + acc = (acc >> 6) + 1; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + acc = ssat24(acc); + + dithSquared = acc; + + /* Form the negative difference of the dither values at index and index-1. + * Load the accumulator with this value divided by 2. Ensure saturation is + * applied to the difference calculation. */ + minusLambdaD = qdata_pt->minusLambdaDTable[index]; + + tmp_accL = (1 << 23) - (int32_t)dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = (int32_t)tmp_acc.s32.l << 8; + + acc = (tmp_acc.u32.l >> 22) | (tmp_acc.s32.h << 10); + acc++; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + // worst case value for acc = 0x000d3e08 + // no saturation required + + /* Add the threshold table values at index and index-1 to the accumulated + * value. */ + acc += qdata_pt->thresholdTablePtr_sl1[index + 1] >> 1; + //// worst case value for acc = 0x000d3e08 + 0x43E1DB = 511FE3 + acc += qdata_pt->thresholdTablePtr_sl1[index] >> 1; + //// worst case value for acc = 0x511FE3 + 0x362FEC = 874FCF + + /* Form the threshold table difference at index and index-1. Ensure + * saturation is applied to the difference calculation. */ + threshDiff = qdata_pt->thresholdTablePtr_sl1[index + 1] - qdata_pt->thresholdTablePtr_sl1[index]; + + /* Based on the sign of the difference signal, either add or subtract the + * threshold table difference from the accumulated value. Recover the final + * accumulated value (saturated/rounded) */ + if (diffSignal < 0) + threshDiff = -threshDiff; + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)threshDiff); + tmp_reg64.s32.h += acc; + acc = tmp_reg64.s32.h; + + if (tmp_reg64.u32.l >= 0x80000000) + acc++; + tmp_round0 = (tmp_reg64.u32.l >> 1) | (tmp_reg64.s32.h << 31); + + acc = ssat24(acc); + + if (tmp_round0 == 0x40000000L) + acc--; + _delta = -delta << 8; + + acc = acc << 4; + + /* Form (absDiffSignal * 0.125) - (acc * delta), which is the final distance + * signal used to determine if dithering alters the quantised code value or + * not. */ + // worst case value for delta is 0x7d400 + tmp_reg64.s64 = ((int64_t)acc * (int64_t)_delta); + tmp_reg64.s32.h += absDiffSignal; + tmp_round0 = (tmp_reg64.u32.l >> 4) | (tmp_reg64.s32.h << 28); + acc = tmp_reg64.s32.h + (1 << 2); + acc >>= 3; + if (tmp_round0 == 0x40000000L) + { + acc--; + } + + tmp_qCode = qdata_pt->qCode; + tmp_altQcode = tmp_qCode - 1; + /* Check the sign of the distance penalty. Get the sign from the + * full-precision accumulator, as done in the Kalimba code. */ + if (tmp_reg64.s32.h < 0) + { + /* The distance is -ve. The optimum code needs decremented by 1 and the + * alternative code is 1 greater than this. Get the rounded version of the + * -ve distance penalty and negate this (form distance magnitude) before + * writing the value out */ + tmp_qCode = tmp_altQcode; + tmp_altQcode++; + acc = -acc; + } + + qdata_pt->distPenalty = acc; + /* If the difference signal is negative, bitwise invert the code (restores + * sign to the magnitude). */ + if (diffSignal < 0) + { + tmp_qCode = ~tmp_qCode; + tmp_altQcode = ~tmp_altQcode; + } + qdata_pt->altQcode = tmp_altQcode; + qdata_pt->qCode = tmp_qCode; +} + +void quantiseDifferenceLL(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt) +{ + int32_t absDiffSignal; + int32_t absDiffSignalShifted; + int32_t index; + int32_t dithSquared; + int32_t minusLambdaD; + int32_t acc; + int32_t threshDiff; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL; + int32_t tmp_qCode; + int32_t tmp_altQcode; + uint32_t tmp_round0; + int32_t _delta; + + /* Form the absolute value of the difference signal and maintain a version + * that is right-shifted 4 places for delta scaling. */ + absDiffSignal = -diffSignal; + if (diffSignal >= 0) absDiffSignal = diffSignal; + absDiffSignal = ssat24(absDiffSignal); + absDiffSignalShifted = absDiffSignal >> deltaScale; + + /* Binary search for the quantised code. This search terminates with the + * table index of the LARGEST threshold table value for which + * absDiffSignalShifted >= (delta * threshold) + */ + index = BsearchLL(absDiffSignalShifted, delta, qdata_pt->thresholdTablePtr_sl1); + + /* We actually wanted the SMALLEST magnitude quantised code for which + * absDiffSignalShifted < (delta * threshold) + * i.e. the code with the next highest magnitude than the one we actually + * found. We could add +1 to the code magnitude to do this, but we need to + * subtract 1 from the code magnitude to compensate for the "phantom + * element" at the base of the quantisation table. These two effects cancel + * out, so we leave the value of code alone. However, we need to form code+1 + * to get the proper index into the both the threshold and dither tables, + * since we must skip over the phantom element at the base. */ + qdata_pt->qCode = index; + + /* Square the dither and get the value back from the ALU + * (saturated/rounded). */ + tmp_acc.s64 = ((int64_t)ditherVal * (int64_t)ditherVal); + + acc = tmp_acc.s32.h; + + tmp_round0 = (uint32_t)acc << 8; + + acc = (acc >> 6) + 1; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + acc = ssat24(acc); + + dithSquared = acc; + + /* Form the negative difference of the dither values at index and index-1. + * Load the accumulator with this value divided by 2. Ensure saturation is + * applied to the difference calculation. */ + minusLambdaD = qdata_pt->minusLambdaDTable[index]; + + tmp_accL = (1 << 23) - (int32_t)dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = (int32_t)tmp_acc.s32.l << 8; + + tmp_acc.s64 >>= 22; + acc = tmp_acc.s32.l; + acc++; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + // worst case value for acc = 0x000d3e08 + // no saturation required + + /* Add the threshold table values at index and index-1 to the accumulated + * value. */ + acc += qdata_pt->thresholdTablePtr_sl1[index + 1] >> 1; + //// worst case value for acc = 0x000d3e08 + 0x43E1DB = 511FE3 + acc += qdata_pt->thresholdTablePtr_sl1[index] >> 1; + //// worst case value for acc = 0x511FE3 + 0x362FEC = 874FCF + + /* Form the threshold table difference at index and index-1. Ensure + * saturation is applied to the difference calculation. */ + threshDiff = qdata_pt->thresholdTablePtr_sl1[index + 1] - qdata_pt->thresholdTablePtr_sl1[index]; + + /* Based on the sign of the difference signal, either add or subtract the + * threshold table difference from the accumulated value. Recover the final + * accumulated value (saturated/rounded) */ + if (diffSignal < 0) + threshDiff = -threshDiff; + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)threshDiff); + tmp_reg64.s32.h += acc; + acc = tmp_reg64.s32.h; + + if (tmp_reg64.u32.l >= 0x80000000) + acc++; + tmp_round0 = (tmp_reg64.u32.l >> 1) | (tmp_reg64.s32.h << 31); + + acc = ssat24(acc); + + if (tmp_round0 == 0x40000000L) + acc--; + _delta = -delta << 8; + + acc = acc << 4; + /* Form (absDiffSignal * 0.125) - (acc * delta), which is the final distance + * signal used to determine if dithering alters the quantised code value or + * not. */ + // worst case value for delta is 0x7d400 + + tmp_reg64.s64 = ((int64_t)acc * (int64_t)_delta); + tmp_reg64.s32.h += absDiffSignal; + tmp_round0 = (tmp_reg64.u32.l >> 4) | (tmp_reg64.s32.h << 28); + acc = tmp_reg64.s32.h + (1 << 2); + acc >>= 3; + if (tmp_round0 == 0x40000000L) + { + acc--; + } + + tmp_qCode = qdata_pt->qCode; + tmp_altQcode = tmp_qCode - 1; + /* Check the sign of the distance penalty. Get the sign from the + * full-precision accumulator, as done in the Kalimba code. */ + if (tmp_reg64.s32.h < 0) + { + /* The distance is -ve. The optimum code needs decremented by 1 and the + * alternative code is 1 greater than this. Get the rounded version of the + * -ve distance penalty and negate this (form distance magnitude) before + * writing the value out */ + tmp_qCode = tmp_altQcode; + tmp_altQcode++; + acc = -acc; + } + + qdata_pt->distPenalty = acc; + /* If the difference signal is negative, bitwise invert the code (restores + * sign to the magnitude). */ + if (diffSignal < 0) + { + tmp_qCode = ~tmp_qCode; + tmp_altQcode = ~tmp_altQcode; + } + qdata_pt->altQcode = tmp_altQcode; + qdata_pt->qCode = tmp_qCode; +} + +void quantiseDifferenceLH(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt) +{ + int32_t absDiffSignal; + int32_t absDiffSignalShifted; + int32_t index; + int32_t dithSquared; + int32_t minusLambdaD; + int32_t acc; + int32_t threshDiff; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL; + int32_t tmp_qCode; + int32_t tmp_altQcode; + uint32_t tmp_round0; + int32_t _delta; + + /* Form the absolute value of the difference signal and maintain a version + * that is right-shifted 4 places for delta scaling. */ + absDiffSignal = -diffSignal; + if (diffSignal >= 0) absDiffSignal = diffSignal; + absDiffSignal = ssat24(absDiffSignal); + absDiffSignalShifted = absDiffSignal >> deltaScale; + + /* Binary search for the quantised code. This search terminates with the + * table index of the LARGEST threshold table value for which + * absDiffSignalShifted >= (delta * threshold) + */ + index = BsearchLH(absDiffSignalShifted, delta, qdata_pt->thresholdTablePtr_sl1); + + /* We actually wanted the SMALLEST magnitude quantised code for which + * absDiffSignalShifted < (delta * threshold) + * i.e. the code with the next highest magnitude than the one we actually + * found. We could add +1 to the code magnitude to do this, but we need to + * subtract 1 from the code magnitude to compensate for the "phantom + * element" at the base of the quantisation table. These two effects cancel + * out, so we leave the value of code alone. However, we need to form code+1 + * to get the proper index into the both the threshold and dither tables, + * since we must skip over the phantom element at the base. */ + qdata_pt->qCode = index; + + /* Square the dither and get the value back from the ALU + * (saturated/rounded). */ + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)ditherVal); + + acc = tmp_reg64.s32.h; + + tmp_round0 = (uint32_t)acc << 8; + + acc = (acc >> 6) + 1; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + acc = ssat24(acc); + + dithSquared = acc; + + /* Form the negative difference of the dither values at index and index-1. + * Load the accumulator with this value divided by 2. Ensure saturation is + * applied to the difference calculation. */ + minusLambdaD = qdata_pt->minusLambdaDTable[index]; + + tmp_accL = (1 << 23) - (int32_t)dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = (int32_t)tmp_acc.s32.l << 8; + + acc = (tmp_acc.u32.l >> 22) | (tmp_acc.s32.h << 10); + if (tmp_round0 == 0x40000000L) + acc -= 2; + acc++; + + // worst case value for acc = 0x000d3e08 + // no saturation required + /* Add the threshold table values at index and index-1 to the accumulated + * value. */ + acc += qdata_pt->thresholdTablePtr_sl1[index + 1]; + //// worst case value for acc = 0x000d3e08 + 0x43E1DB = 511FE3 + acc += qdata_pt->thresholdTablePtr_sl1[index]; + acc >>= 1; + + /* Form the threshold table difference at index and index-1. Ensure + * saturation is applied to the difference calculation. */ + threshDiff = qdata_pt->thresholdTablePtr_sl1[index + 1] - qdata_pt->thresholdTablePtr_sl1[index]; + + /* Based on the sign of the difference signal, either add or subtract the + * threshold table difference from the accumulated value. Recover the final + * accumulated value (saturated/rounded) */ + if (diffSignal < 0) + threshDiff = -threshDiff; + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)threshDiff); + + tmp_reg64.s32.h += acc; + acc = tmp_reg64.s32.h; + + if (tmp_reg64.u32.l >= 0x80000000) + acc++; + tmp_round0 = (tmp_reg64.u32.l >> 1) | (tmp_reg64.s32.h << 31); + + acc = ssat24(acc); + + if (tmp_round0 == 0x40000000L) + acc--; + _delta = -delta << 8; + + acc = acc << 4; + + /* Form (absDiffSignal * 0.125) - (acc * delta), which is the final distance + * signal used to determine if dithering alters the quantised code value or + * not. */ + // worst case value for delta is 0x7d400 + tmp_reg64.s64 = ((int64_t)acc * (int64_t)_delta); + tmp_reg64.s32.h += absDiffSignal; + tmp_round0 = (tmp_reg64.u32.l >> 4) | (tmp_reg64.s32.h << 28); + acc = tmp_reg64.s32.h + (1 << 2); + acc >>= 3; + if (tmp_round0 == 0x40000000L) + { + acc--; + } + + tmp_qCode = qdata_pt->qCode; + tmp_altQcode = tmp_qCode - 1; + /* Check the sign of the distance penalty. Get the sign from the + * full-precision accumulator, as done in the Kalimba code. */ + + if (tmp_reg64.s32.h < 0) + { + /* The distance is -ve. The optimum code needs decremented by 1 and the + * alternative code is 1 greater than this. Get the rounded version of the + * -ve distance penalty and negate this (form distance magnitude) before + * writing the value out */ + tmp_qCode = tmp_altQcode; + tmp_altQcode++; + acc = -acc; + } + + qdata_pt->distPenalty = acc; + /* If the difference signal is negative, bitwise invert the code (restores + * sign to the magnitude). */ + if (diffSignal < 0) + { + tmp_qCode = ~tmp_qCode; + tmp_altQcode = ~tmp_altQcode; + } + qdata_pt->altQcode = tmp_altQcode; + qdata_pt->qCode = tmp_qCode; +} diff --git a/system/embdrv/encoder_for_aptx/src/Quantiser.h b/system/embdrv/encoder_for_aptx/src/Quantiser.h new file mode 100644 index 00000000000..63a32c65905 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/Quantiser.h @@ -0,0 +1,27 @@ +/*------------------------------------------------------------------------------ + * + * Function to calculate a quantised representation of an input + * difference signal, based on additional dither values and step-size inputs. + * + *-----------------------------------------------------------------------------*/ + +#ifndef QUANTISER_H +#define QUANTISER_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +#include "AptxParameters.h" + + +void quantiseDifferenceLL(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt); +void quantiseDifferenceHL(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt); +void quantiseDifferenceLH(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt); +void quantiseDifferenceHH(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt); + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //QUANTISER_H diff --git a/system/embdrv/encoder_for_aptx/src/SubbandFunctions.h b/system/embdrv/encoder_for_aptx/src/SubbandFunctions.h new file mode 100644 index 00000000000..b8e743d480c --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/SubbandFunctions.h @@ -0,0 +1,184 @@ +/*------------------------------------------------------------------------------ + * + * Subband processing consists of: + * inverse quantisation (defined in a separate file), + * predictor coefficient update (Pole and Zero Coeff update), + * predictor filtering. + * + *----------------------------------------------------------------------------*/ + +#ifndef SUBBANDFUNCTIONS_H +#define SUBBANDFUNCTIONS_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +#include "AptxParameters.h" + + +XBT_INLINE_ void updatePredictorPoleCoefficients(const int32_t invQ, const int32_t prevZfiltOutput, PoleCoeff_data* PoleCoeffDataPt) +{ + int32_t adaptSum; + int32_t sgnP[3]; + int32_t newCoeffs[2]; + int32_t Bacc; + int32_t acc; + int32_t acc2; + int32_t tmp3_round0; + int16_t tmp2_round0; + int16_t tmp_round0; + /* Various constants in various Q formats */ + const int32_t oneQ22 = 4194304L; + const int32_t minusOneQ22 = -4194304L; + const int32_t pointFiveQ21 = 1048576L; + const int32_t minusPointFiveQ21 = -1048576L; + const int32_t pointSevenFiveQ22 = 3145728L; + const int32_t minusPointSevenFiveQ22 = -3145728L; + const int32_t oneMinusTwoPowerMinusFourQ22 = 3932160L; + + /* Symbolic indicies for the pole coefficient arrays. Here we are using a1 + * to represent the first pole filter coefficient and a2 the second. This + * seems to be common ADPCM terminology. */ + enum { a1 = 0, a2 = 1 }; + + /* Symbolic indicies for the sgn array (k, k-1 and k-2 respectively) */ + enum { k = 0, k_1 = 1, k_2 = 2 }; + + /* Form the sum of the inverse quantiser and previous zero filter values */ + adaptSum = invQ + prevZfiltOutput; + adaptSum = ssat24(adaptSum); + + /* Form the sgn of the sum just formed (note +1 and -1 are Q22) */ + if (adaptSum < 0L) + { + sgnP[k] = minusOneQ22; + sgnP[k_1] = -(((int32_t)PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l) << 22); + sgnP[k_2] = -(((int32_t)PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h) << 22); + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h = PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l = -1; + } + if (adaptSum == 0L) + { + sgnP[k] = 0L; + sgnP[k_1] = 0L; + sgnP[k_2] = 0L; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h = PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l = 1; + } + if (adaptSum > 0L) + { + sgnP[k] = oneQ22; + sgnP[k_1] = ((int32_t)PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l) << 22; + sgnP[k_2] = ((int32_t)PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h) << 22; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h = PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l = 1; + } + + /* Clear the accumulator and form -a1(k) * sgn(p(k))sgn(p(k-1)) in Q21. Clip + * it to +/- 0.5 (Q21) so that we can take f(a1) = 4 * a1. This is a partial + * result for the new a2 */ + acc = 0; + acc -= PoleCoeffDataPt->m_poleCoeff[a1] * (sgnP[k_1] >> 22); + + tmp3_round0 = acc & 0x3L; + + acc += 0x001; + acc >>= 1; + if (tmp3_round0 == 0x001L) + { + acc--; + } + + newCoeffs[a2] = acc; + + if (newCoeffs[a2] < minusPointFiveQ21) + { + newCoeffs[a2] = minusPointFiveQ21; + } + if (newCoeffs[a2] > pointFiveQ21) + { + newCoeffs[a2] = pointFiveQ21; + } + + /* Load the accumulator with sgn(p(k))sgn(p(k-2)) right-shifted by 3. The + * 3-position shift is to multiply it by 0.25 and convert from Q22 to Q21. + * */ + Bacc = (sgnP[k_2] >> 3); + /* Add the current a2 update value to the accumulator (Q21) */ + Bacc += newCoeffs[a2]; + /* Shift the accumulator right by 4 positions. + * Right 7 places to multiply by 2^(-7) + * Left 2 places to scale by 4 (0.25A + B -> A + 4B) + * Left 1 place to convert from Q21 to Q22 + */ + Bacc >>= 4; + /* Add a2(k-1) * (1 - 2^(-7)) to the accumulator. Note that the constant is + * expressed as Q23, hence the product is Q22. Get the accumulator value + * back out. */ + acc2 = PoleCoeffDataPt->m_poleCoeff[a2] << 8; + acc2 -= PoleCoeffDataPt->m_poleCoeff[a2] << 1; + Bacc <<= 8; + Bacc += acc2; + + tmp2_round0 = (int16_t)Bacc & 0x01FFL; + + Bacc += 0x0080L; + Bacc >>= 8; + + if (tmp2_round0 == 0x0080L) + { + Bacc--; + } + + newCoeffs[a2] = Bacc; + + /* Clip the new a2(k) value to +/- 0.75 (Q22) */ + if (newCoeffs[a2] < minusPointSevenFiveQ22) + { + newCoeffs[a2] = minusPointSevenFiveQ22; + } + if (newCoeffs[a2] > pointSevenFiveQ22) + { + newCoeffs[a2] = pointSevenFiveQ22; + } + PoleCoeffDataPt->m_poleCoeff[a2] = newCoeffs[a2]; + + /* Form sgn(p(k))sgn(p(k-1)) * (3 * 2^(-8)). The constant is Q23, hence the + * product is Q22. */ + /* Add a1(k-1) * (1 - 2^(-8)) to the accumulator. The constant is Q23, hence + * the product is Q22. Get the value from the accumulator. */ + acc2 = PoleCoeffDataPt->m_poleCoeff[a1] << 8; + acc2 -= PoleCoeffDataPt->m_poleCoeff[a1]; + acc2 += (sgnP[k_1] << 2); + acc2 -= (sgnP[k_1]); + + tmp_round0 = (int16_t)acc2 & 0x01FF; + + acc2 += 0x0080; + acc = (acc2 >> 8); + if (tmp_round0 == 0x0080) + { + acc--; + } + + newCoeffs[a1] = (int32_t)acc; + + /* Clip the new value of a1(k) to +/- (1 - 2^4 - a2(k)). The constant 1 - + * 2^4 is expressed in Q22 format (as is a1 and a2) */ + if (newCoeffs[a1] < (newCoeffs[a2] - oneMinusTwoPowerMinusFourQ22)) + { + newCoeffs[a1] = newCoeffs[a2] - oneMinusTwoPowerMinusFourQ22; + } + if (newCoeffs[a1] > (oneMinusTwoPowerMinusFourQ22 - newCoeffs[a2])) + { + newCoeffs[a1] = oneMinusTwoPowerMinusFourQ22 - newCoeffs[a2]; + } + PoleCoeffDataPt->m_poleCoeff[a1] = newCoeffs[a1]; +} + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //SUBBANDFUNCTIONS_H diff --git a/system/embdrv/encoder_for_aptx/src/SubbandFunctionsCommon.h b/system/embdrv/encoder_for_aptx/src/SubbandFunctionsCommon.h new file mode 100644 index 00000000000..3f8f05e240d --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/SubbandFunctionsCommon.h @@ -0,0 +1,515 @@ +/*------------------------------------------------------------------------------ + * + * Subband processing consists of: + * inverse quantisation (defined in a separate file), + * predictor coefficient update (Pole and Zero Coeff update), + * predictor filtering. + * + *----------------------------------------------------------------------------*/ + +#ifndef SUBBANDFUNCTIONSCOMMON_H +#define SUBBANDFUNCTIONSCOMMON_H + + +enum reg64_reg{reg64_H=1,reg64_L=0}; + +void processSubband(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt); +void processSubbandLL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt); +void processSubbandHL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt); + + +/* Function to carry out inverse quantisation for LL, LH and HH subband types */ +XBT_INLINE_ void invertQuantisation(const int32_t qCode, const int32_t ditherVal, IQuantiser_data* iqdata_pt) +{ + int32_t invQ; + int32_t index; + int32_t acc; + reg64_t tmp_r64; + int64_t tmp_acc; + int32_t tmp_accL; + int32_t tmp_accH; + uint32_t tmp_round0; + uint32_t tmp_round1; + + unsigned u16t; + /* log delta leak value (Q23) */ + const uint32_t logDeltaLeakVal = 0x7F6CL; + + /* Turn the quantised code back into an index into the threshold table. This + * involves bitwise inversion of the code (if -ve) and adding 1 (phantom + * element at table base). Then set invQ to be +/- the threshold value, + * depending on the code sign. */ + index = qCode; + if (qCode < 0) + index = (~index); + index = index + 1; + invQ = iqdata_pt->thresholdTablePtr_sl1[index]; + if (qCode < 0) + invQ = -invQ; + + /* Load invQ into the accumulator. Add the product of the dither value times + * the indexed dither table value. Then get the result back from the + * accumulator as an updated invQ. */ + tmp_r64.s64 = ((int64_t)ditherVal * iqdata_pt->ditherTablePtr_sf1[index]); + tmp_r64.s32.h += invQ >> 1; + + acc = tmp_r64.s32.h; + + tmp_round1 = tmp_r64.s32.h & 0x00000001L; + if (tmp_r64.u32.l >= 0x80000000) + acc++; + if (tmp_round1 == 0 && tmp_r64.s32.l == (int32_t)0x80000000L) + acc--; + acc = ssat24(acc); + + invQ = (int32_t)acc; + + /* Scale invQ by the current delta value. Left-shift the result (in the + * accumulator) by 4 positions for the delta scaling. Get the updated invQ + * back from the accumulator. */ + + u16t = iqdata_pt->logDelta; + tmp_acc = ((int64_t)invQ * iqdata_pt->delta); + tmp_accL = u16t * logDeltaLeakVal; + tmp_accH = iqdata_pt->incrTablePtr[index]; + acc = (int32_t)(tmp_acc >> (23 - deltaScale)); + invQ = ssat24(acc); + + /* Now update the value of logDelta. Load the accumulator with the index + * value of the logDelta increment table. Add the product of the current + * logDelta scaled by a leaky coefficient (16310 in Q14). Get the value back + * from the accumulator. */ + tmp_accH += tmp_accL >> (32 - 17); + + acc = tmp_accH; + + tmp_r64.u32.l = ((uint32_t)tmp_accL << 17); + tmp_r64.s32.h = tmp_accH; + + tmp_round0 = tmp_r64.u32.l; + tmp_round1 = (int32_t)(tmp_r64.u64 >> 1); + if (tmp_round0 >= 0x80000000L) + acc++; + if (tmp_round1 == 0x40000000L) + acc--; + + /* Limit the updated logDelta between 0 and its subband-specific maximum. */ + if (acc < 0) + acc = 0; + if (acc > iqdata_pt->maxLogDelta) + acc = iqdata_pt->maxLogDelta; + + iqdata_pt->logDelta = (uint16_t)acc; + + /* The updated value of delta is the logTable output (indexed by 5 bits from + * the updated logDelta) shifted by a value involving the logDelta minimum + * and the updated logDelta itself. */ + iqdata_pt->delta = iqdata_pt->iquantTableLogPtr[(acc >> 3) & 0x1f] >> + (22 - 25 - iqdata_pt->minLogDelta - (acc >> 8)); + + iqdata_pt->invQ = invQ; +} + +/* Function to carry out inverse quantisation for a HL subband type */ +XBT_INLINE_ void invertQuantisationHL(const int32_t qCode, const int32_t ditherVal, IQuantiser_data* iqdata_pt) +{ + int32_t invQ; + int32_t index; + int32_t acc; + reg64_t tmp_r64; + int64_t tmp_acc; + int32_t tmp_accL; + int32_t tmp_accH; + uint32_t tmp_round0; + uint32_t tmp_round1; + + unsigned u16t; + /* log delta leak value (Q23) */ + const uint32_t logDeltaLeakVal = 0x7F6CL; + + /* Turn the quantised code back into an index into the threshold table. This + * involves bitwise inversion of the code (if -ve) and adding 1 (phantom + * element at table base). Then set invQ to be +/- the threshold value, + * depending on the code sign. */ + index = qCode; + if (qCode < 0) + index = (~index); + index = index + 1; + invQ = iqdata_pt->thresholdTablePtr_sl1[index]; + if (qCode < 0) + invQ = -invQ; + + /* Load invQ into the accumulator. Add the product of the dither value times + * the indexed dither table value. Then get the result back from the + * accumulator as an updated invQ. */ + tmp_r64.s64 = ((int64_t)ditherVal * iqdata_pt->ditherTablePtr_sf1[index]); + tmp_r64.s32.h += invQ >> 1; + + acc = tmp_r64.s32.h; + + tmp_round1 = tmp_r64.s32.h & 0x00000001L; + if (tmp_r64.u32.l >= 0x80000000) + acc++; + if (tmp_round1 == 0 && tmp_r64.u32.l == 0x80000000L) + acc--; + acc = ssat24(acc); + + invQ = (int32_t)acc; + + /* Scale invQ by the current delta value. Left-shift the result (in the + * accumulator) by 4 positions for the delta scaling. Get the updated invQ + * back from the accumulator. */ + u16t = iqdata_pt->logDelta; + tmp_acc = ((int64_t)invQ * iqdata_pt->delta); + tmp_accL = u16t * logDeltaLeakVal; + tmp_accH = iqdata_pt->incrTablePtr[index]; + acc = (int32_t)(tmp_acc >> (23 - deltaScale)); + invQ = acc; + + /* Now update the value of logDelta. Load the accumulator with the index + * value of the logDelta increment table. Add the product of the current + * logDelta scaled by a leaky coefficient (16310 in Q14). Get the value back + * from the accumulator. */ + tmp_accH += tmp_accL >> (32 - 17); + + acc = tmp_accH; + + tmp_r64.u32.l = ((uint32_t)tmp_accL << 17); + tmp_r64.s32.h = tmp_accH; + + tmp_round0 = tmp_r64.u32.l; + tmp_round1 = (int32_t)(tmp_r64.u64 >> 1); + if (tmp_round0 >= 0x80000000L) + acc++; + if (tmp_round1 == 0x40000000L) + acc--; + + /* Limit the updated logDelta between 0 and its subband-specific maximum. */ + if (acc < 0) + acc = 0; + if (acc > iqdata_pt->maxLogDelta) + acc = iqdata_pt->maxLogDelta; + + iqdata_pt->logDelta = (uint16_t)acc; + + /* The updated value of delta is the logTable output (indexed by 5 bits from + * the updated logDelta) shifted by a value involving the logDelta minimum + * and the updated logDelta itself. */ + iqdata_pt->delta = iqdata_pt->iquantTableLogPtr[(acc >> 3) & 0x1f] >> + (22 - 25 - iqdata_pt->minLogDelta - (acc >> 8)); + + iqdata_pt->invQ = invQ; +} + +/* Function to carry out prediction ARMA filtering for the current subband + * performPredictionFiltering should only be used for HH and LH subband! */ +XBT_INLINE_ void performPredictionFiltering(const int32_t invQ, Subband_data* SubbandDataPt) +{ + int32_t poleVal; + int32_t acc; + int64_t accL; + uint32_t pointer; + int32_t poleDelayLine; + int32_t predVal; + int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff; + int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff; + int32_t zData0; + int32_t* cbuf_pt; + int32_t invQincr_pos; + int32_t invQincr_neg; + int32_t k; + int32_t oldZData; + /* Pole coefficient and data indicies */ + enum { a1 = 0, a2 = 1 }; + + /* Write the newest pole input sample to the pole delay line. + * Ensure the sum of the current dequantised error and the previous + * predictor output is saturated if necessary. */ + poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal; + + poleDelayLine = ssat24(poleDelayLine); + + /* Pole filter convolution. Shift convolution result 1 place to the left + * before retrieving it, since the pole coefficients are Q22 (data is Q23) + * and we want a Q23 result */ + accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]); + /* Update the pole delay line for the next pass by writing the new input + * sample into the 2nd element */ + SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine; + accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine); + poleVal = (int32_t)(accL >> 22); + poleVal = ssat24(poleVal); + + /* Create (2^(-7)) * sgn(invQ) in Q22 format. */ + if (invQ == 0) + { + invQincr_pos = 0L; + } + else + { + invQincr_pos = 0x800000; + } + if (invQ < 0L) + { + invQincr_pos = -invQincr_pos; + } + + invQincr_neg = 0x0080 - invQincr_pos; + invQincr_pos += 0x0080; + + pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 12; + cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer]; + /* partial manual unrolling to improve performance */ + if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 12) + SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0; + + SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ; + + /* Iterate over the number of coefficients for this subband */ + oldZData = invQ; + accL = 0; + for (k = 0; k < 12; k++) + { + uint32_t tmp_round0; + int32_t coeffValue; + + zData0 = (*(cbuf_pt--)); + coeffValue = *(zeroCoeffPt + k); + if (zData0 < 0L) + { + acc = invQincr_neg - coeffValue; + } + else + { + acc = invQincr_pos - coeffValue; + } + tmp_round0 = acc; + acc = (acc >> 8) + coeffValue; + if (((tmp_round0 << 23) ^ 0x80000000) == 0) acc--; + accL += (int64_t)acc * (int64_t)(oldZData); + oldZData = zData0; + *(zeroCoeffPt + k) = acc; + } + + acc = (int32_t)(accL >> 22); + acc = ssat24(acc); + /* Predictor output is the sum of the pole and zero filter outputs. Ensure + * this is saturated, if necessary. */ + predVal = acc + poleVal; + predVal = ssat24(predVal); + SubbandDataPt->m_predData.m_zeroVal = acc; + SubbandDataPt->m_predData.m_predVal = predVal; + + /* Update the zero filter delay line by writing the new input sample to the + * circular buffer. */ + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 12] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; +} + +XBT_INLINE_ void performPredictionFilteringLL(const int32_t invQ, Subband_data* SubbandDataPt) +{ + int32_t poleVal; + int32_t acc; + int64_t accL; + uint32_t pointer; + int32_t poleDelayLine; + int32_t predVal; + int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff; + int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff; + int32_t* cbuf_pt; + int32_t invQincr_pos; + int32_t invQincr_neg; + int32_t k; + int32_t oldZData; + /* Pole coefficient and data indicies */ + enum { a1 = 0, a2 = 1 }; + + /* Write the newest pole input sample to the pole delay line. + * Ensure the sum of the current dequantised error and the previous + * predictor output is saturated if necessary. */ + poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal; + + poleDelayLine = ssat24(poleDelayLine); + + /* Pole filter convolution. Shift convolution result 1 place to the left + * before retrieving it, since the pole coefficients are Q22 (data is Q23) + * and we want a Q23 result */ + accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]); + /* Update the pole delay line for the next pass by writing the new input + * sample into the 2nd element */ + SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine; + accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine); + poleVal = (int32_t)(accL >> 22); + poleVal = ssat24(poleVal); + // store poleVal to free one register. + SubbandDataPt->m_predData.m_predVal = poleVal; + + /* Create (2^(-7)) * sgn(invQ) in Q22 format. */ + if (invQ == 0) + { + invQincr_pos = 0L; + } + else + { + invQincr_pos = 0x800000; + } + if (invQ < 0L) + { + invQincr_pos = -invQincr_pos; + } + + invQincr_neg = 0x0080 - invQincr_pos; + invQincr_pos += 0x0080; + + pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 24; + cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer]; + /* partial manual unrolling to improve performance */ + if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 24) + SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0; + + SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ; + + /* Iterate over the number of coefficients for this subband */ + + oldZData = invQ; + accL = 0; + for (k = 0; k < 24; k++) + { + int32_t zData0; + int32_t coeffValue; + + zData0 = (*(cbuf_pt--)); + coeffValue = *(zeroCoeffPt + k); + if (zData0 < 0L) { + acc = invQincr_neg - coeffValue; + } + else { + acc = invQincr_pos - coeffValue; + } + if (((acc << 23) ^ 0x80000000) == 0) coeffValue--; + acc = (acc >> 8) + coeffValue; + accL += (int64_t)acc * (int64_t)(oldZData); + oldZData = zData0; + *(zeroCoeffPt + k) = acc; + } + + acc = (int32_t)(accL >> 22); + acc = ssat24(acc); + /* Predictor output is the sum of the pole and zero filter outputs. Ensure + * this is saturated, if necessary. */ + // recover value of PoleVal stored at beginning of routine... + predVal = acc + SubbandDataPt->m_predData.m_predVal; + predVal = ssat24(predVal); + SubbandDataPt->m_predData.m_zeroVal = acc; + SubbandDataPt->m_predData.m_predVal = predVal; + + /* Update the zero filter delay line by writing the new input sample to the + * circular buffer. */ + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 24] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; +} + +XBT_INLINE_ void performPredictionFilteringHL(const int32_t invQ, Subband_data* SubbandDataPt) +{ + int32_t poleVal; + int32_t acc; + int64_t accL; + uint32_t pointer; + int32_t poleDelayLine; + int32_t predVal; + int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff; + int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff; + int32_t zData0; + int32_t* cbuf_pt; + int32_t invQincr_pos; + int32_t invQincr_neg; + int32_t k; + int32_t oldZData; + const int32_t roundCte = 0x80000000; + /* Pole coefficient and data indicies */ + enum { a1 = 0, a2 = 1 }; + + /* Write the newest pole input sample to the pole delay line. + * Ensure the sum of the current dequantised error and the previous + * predictor output is saturated if necessary. */ + poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal; + + poleDelayLine = ssat24(poleDelayLine); + + /* Pole filter convolution. Shift convolution result 1 place to the left + * before retrieving it, since the pole coefficients are Q22 (data is Q23) + * and we want a Q23 result */ + accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]); + /* Update the pole delay line for the next pass by writing the new input + * sample into the 2nd element */ + SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine; + accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine); + poleVal = (int32_t)(accL >> 22); + poleVal = ssat24(poleVal); + + /* Create (2^(-7)) * sgn(invQ) in Q22 format. */ + invQincr_pos = 0L; + if (invQ != 0) + { + invQincr_pos = 0x800000; + } + if (invQ < 0L) + { + invQincr_pos = -invQincr_pos; + } + + invQincr_neg = 0x0080 - invQincr_pos; + invQincr_pos += 0x0080; + + pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 6; + cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer]; + /* partial manual unrolling to improve performance */ + if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 6) + SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0; + + SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ; + + /* Iterate over the number of coefficients for this subband */ + oldZData = invQ; + accL = 0; + + for (k = 0; k < 6; k++) + { + uint32_t tmp_round0; + int32_t coeffValue; + + zData0 = (*(cbuf_pt--)); + coeffValue = *(zeroCoeffPt + k); + if (zData0 < 0L) + { + acc = invQincr_neg - coeffValue; + } + else + { + acc = invQincr_pos - coeffValue; + } + tmp_round0 = acc; + acc = (acc >> 8) + coeffValue; + if (((tmp_round0 << 23) ^ roundCte) == 0) acc--; + accL += (int64_t)acc * (int64_t)(oldZData); + oldZData = zData0; + *(zeroCoeffPt + k) = acc; + } + + acc = (int32_t)(accL >> 22); + acc = ssat24(acc); + /* Predictor output is the sum of the pole and zero filter outputs. Ensure + * this is saturated, if necessary. */ + predVal = acc + poleVal; + predVal = ssat24(predVal); + SubbandDataPt->m_predData.m_zeroVal = acc; + SubbandDataPt->m_predData.m_predVal = predVal; + + /* Update the zero filter delay line by writing the new input sample to the + * circular buffer. */ + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 6] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; +} + + +#endif //SUBBANDFUNCTIONSCOMMON_H diff --git a/system/embdrv/encoder_for_aptx/src/SyncInserter.h b/system/embdrv/encoder_for_aptx/src/SyncInserter.h new file mode 100644 index 00000000000..347fd50b49e --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/SyncInserter.h @@ -0,0 +1,217 @@ +/*------------------------------------------------------------------------------ + * + * All declarations relevant for the SyncInserter class. This class exposes a + * public interface that lets a client supply two aptX encoder objects (left + * and right stereo channel) and have the current quantised codes adjusted to + * bury an autosync bit. + * + *----------------------------------------------------------------------------*/ + +#ifndef SYNCINSERTER_H +#define SYNCINSERTER_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +#include "AptxParameters.h" + + + +/* Function to insert sync information into one of the 8 quantised codes + * spread across 2 aptX codewords (1 codeword per channel) */ +XBT_INLINE_ void xbtEncinsertSync(Encoder_data* leftChannelEncoder, Encoder_data* rightChannelEncoder, uint32_t* syncWordPhase) +{ + /* Currently using 0x1 as the 8-bit sync pattern */ + static const uint32_t syncWord = 0x1; + uint32_t tmp_var; + + uint32_t i; + + /* Variable to hold the XOR of all the quantised code lsbs */ + uint32_t xorCodeLsbs; + + /* Variable to point to the quantiser with the minimum calculated distance + * penalty. */ + Quantiser_data* minPenaltyQuantiser; + + /* Get the vector of quantiser pointers from the left and right encoders */ + Quantiser_data* leftQuant[4]; + Quantiser_data* rightQuant[4]; + leftQuant[0] = &leftChannelEncoder->m_qdata[0]; + leftQuant[1] = &leftChannelEncoder->m_qdata[1]; + leftQuant[2] = &leftChannelEncoder->m_qdata[2]; + leftQuant[3] = &leftChannelEncoder->m_qdata[3]; + rightQuant[0] = &rightChannelEncoder->m_qdata[0]; + rightQuant[1] = &rightChannelEncoder->m_qdata[1]; + rightQuant[2] = &rightChannelEncoder->m_qdata[2]; + rightQuant[3] = &rightChannelEncoder->m_qdata[3]; + + /* Starting quantiser traversal with the LL quantiser from the left channel. + * Initialise the pointer to the minimum penalty quantiser with the details + * of the left LL quantiser. Initialise the code lsbs XOR variable with the + * left LL quantised code lsbs and also XOR in the left and right random + * dither bit generated by the 2 encoders. */ + xorCodeLsbs = + ((rightQuant[LL]->qCode) & 0x1) ^ + leftChannelEncoder->m_dithSyncRandBit ^ + rightChannelEncoder->m_dithSyncRandBit; + minPenaltyQuantiser = rightQuant[LH]; + + /* Traverse across the LH, HL and HH quantisers from the right channel */ + for (i = LH; i <= HH; i++) + { + /* XOR in the lsb of the quantised code currently examined */ + xorCodeLsbs ^= (rightQuant[i]->qCode) & 0x1; + } + + /* If the distance penalty associated with a quantiser is less than the + * current minimum, then make that quantiser the minimum penalty + * quantiser. */ + if (rightQuant[HL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[HL]; + if (rightQuant[LL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[LL]; + if (rightQuant[HH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[HH]; + + /* Traverse across all quantisers from the left channel */ + for (i = LL; i <= HH; i++) + { + /* XOR in the lsb of the quantised code currently examined */ + xorCodeLsbs ^= (leftQuant[i]->qCode) & 0x1; + } + + /* If the distance penalty associated with a quantiser is less than the + * current minimum, then make that quantiser the minimum penalty + * quantiser. */ + if (leftQuant[LH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[LH]; + if (leftQuant[HL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[HL]; + if (leftQuant[LL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[LL]; + if (leftQuant[HH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[HH]; + + /* If the lsbs of all 8 quantised codes don't happen to equal the desired + * sync bit to embed, then force them to be by replacing the optimum code + * with the alternate code in the minimum penalty quantiser (changes the lsb + * of the code in this quantiser) */ + if (xorCodeLsbs != ((syncWord >> (*syncWordPhase)) & 0x1)) + { + minPenaltyQuantiser->qCode = minPenaltyQuantiser->altQcode; + } + + /* Decrement the selected sync word bit modulo 8 for the next pass. */ + tmp_var = --(*syncWordPhase); + (*syncWordPhase) = tmp_var & 0x7; +} + +XBT_INLINE_ void xbtEncinsertSyncDualMono(Encoder_data* leftChannelEncoder, Encoder_data* rightChannelEncoder, uint32_t* syncWordPhase) +{ + /* Currently using 0x1 as the 8-bit sync pattern */ + static const uint32_t syncWord = 0x1; + uint32_t tmp_var; + + uint32_t i; + + /* Variable to hold the XOR of all the quantised code lsbs */ + uint32_t xorCodeLsbs; + + /* Variable to point to the quantiser with the minimum calculated distance + * penalty. */ + Quantiser_data* minPenaltyQuantiser; + + /* Get the vector of quantiser pointers from the left and right encoders */ + Quantiser_data* leftQuant[4]; + Quantiser_data* rightQuant[4]; + leftQuant[0] = &leftChannelEncoder->m_qdata[0]; + leftQuant[1] = &leftChannelEncoder->m_qdata[1]; + leftQuant[2] = &leftChannelEncoder->m_qdata[2]; + leftQuant[3] = &leftChannelEncoder->m_qdata[3]; + rightQuant[0] = &rightChannelEncoder->m_qdata[0]; + rightQuant[1] = &rightChannelEncoder->m_qdata[1]; + rightQuant[2] = &rightChannelEncoder->m_qdata[2]; + rightQuant[3] = &rightChannelEncoder->m_qdata[3]; + + /* Starting quantiser traversal with the LL quantiser from the left channel. + * Initialise the pointer to the minimum penalty quantiser with the details + * of the left LL quantiser. Initialise the code lsbs XOR variable with the + * left LL quantised code lsbs */ + xorCodeLsbs = leftChannelEncoder->m_dithSyncRandBit; + + minPenaltyQuantiser = leftQuant[LH]; + + /* Traverse across all the quantisers from the left channel */ + for (i = LL; i <= HH; i++) + { + /* XOR in the lsb of the quantised code currently examined */ + xorCodeLsbs ^= (leftQuant[i]->qCode) & 0x1; + } + + /* If the distance penalty associated with a quantiser is less than the + * current minimum, then make that quantiser the minimum penalty + * quantiser. */ + if (leftQuant[LH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[LH]; + if (leftQuant[HL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[HL]; + if (leftQuant[LL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[LL]; + if (leftQuant[HH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[HH]; + + /* If the lsbs of all 4 quantised codes don't happen to equal the desired + * sync bit to embed, then force them to be by replacing the optimum code + * with the alternate code in the minimum penalty quantiser (changes the lsb + * of the code in this quantiser) */ + if (xorCodeLsbs != ((syncWord >> (*syncWordPhase)) & 0x1)) + { + minPenaltyQuantiser->qCode = minPenaltyQuantiser->altQcode; + } + + /**** Insert sync on the Right channel ****/ + xorCodeLsbs = rightChannelEncoder->m_dithSyncRandBit; + + minPenaltyQuantiser = rightQuant[LH]; + + /* Traverse across all quantisers from the right channel */ + for (i = LL; i <= HH; i++) + { + /* XOR in the lsb of the quantised code currently examined */ + xorCodeLsbs ^= (rightQuant[i]->qCode) & 0x1; + } + + /* If the distance penalty associated with a quantiser is less than the + * current minimum, then make that quantiser the minimum penalty + * quantiser. */ + if (rightQuant[LH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[LH]; + if (rightQuant[HL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[HL]; + if (rightQuant[LL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[LL]; + if (rightQuant[HH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[HH]; + + /* If the lsbs of all 4 quantised codes don't happen to equal the desired + * sync bit to embed, then force them to be by replacing the optimum code + * with the alternate code in the minimum penalty quantiser (changes the lsb + * of the code in this quantiser) */ + if (xorCodeLsbs != ((syncWord >> (*syncWordPhase)) & 0x1)) + { + minPenaltyQuantiser->qCode = minPenaltyQuantiser->altQcode; + } + + /* End of Right channel autosync insert*/ + /* Decrement the selected sync word bit modulo 8 for the next pass. */ + tmp_var = --(*syncWordPhase); + (*syncWordPhase) = tmp_var & 0x7; +} + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //SYNCINSERTER_H diff --git a/system/embdrv/encoder_for_aptx/src/aptXbtenc.c b/system/embdrv/encoder_for_aptx/src/aptXbtenc.c new file mode 100644 index 00000000000..4fde99262fb --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/aptXbtenc.c @@ -0,0 +1,218 @@ +#include "AptxParameters.h" +#include "AptxTables.h" +#include "aptXbtenc.h" +#include "AptxEncoder.h" +#include "SyncInserter.h" +#include "CodewordPacker.h" +#include "swversion.h" + + +typedef struct aptxbtenc_t +{ + /* m_endian should either be 0 (little endian) or 8 (big endian). */ + int32_t m_endian; + + /* m_sync_mode is an enumerated type and will be + 0 (stereo sync), + 1 (for dual mono sync), or + 2 (for dual channel with no autosync). + */ + int32_t m_sync_mode; + + /* Autosync inserter & Checker for use with the stereo aptX codec. */ + /* The current phase of the sync word insertion (7 down to 0) */ + uint32_t m_syncWordPhase; + + /* Stereo channel aptX encoder (annotated to produce Kalimba test vectors + * for it's I/O. This will process valid PCM from a WAV file). */ + /* Each Encoder_data structure requires 1592 bytes */ + Encoder_data m_encoderData[2]; + Qmf_storage m_qmf_l; + Qmf_storage m_qmf_r; +}aptxbtenc; + +/* Log to linear lookup table used in inverse quantiser*/ +/* Size of Table: 32*4 = 128 bytes */ +static const int32_t IQuant_tableLogT[32] = +{ + 16384 * 256, 16744 * 256, 17112 * 256, 17488 * 256, + 17864 * 256, 18256 * 256, 18656 * 256, 19064 * 256, + 19480 * 256, 19912 * 256, 20344 * 256, 20792 * 256, + 21248 * 256, 21712 * 256, 22192 * 256, 22672 * 256, + 23168 * 256, 23680 * 256, 24200 * 256, 24728 * 256, + 25264 * 256, 25824 * 256, 26384 * 256, 26968 * 256, + 27552 * 256, 28160 * 256, 28776 * 256, 29408 * 256, + 30048 * 256, 30704 * 256, 31376 * 256, 32064 * 256 +}; + +void clearmem(void* mem, int32_t sz) +{ + int8_t* m = (int8_t*)mem; + int32_t i = 0; + for (; i < sz; i++) + { + *m = 0; + m++; + } +} + +APTXBTENCEXPORT int SizeofAptxbtenc(void) +{ + return (sizeof(aptxbtenc)); +} + +APTXBTENCEXPORT const char* aptxbtenc_version() +{ + return (swversion); +} + +APTXBTENCEXPORT int aptxbtenc_init(void* _state, short endian) +{ + aptxbtenc* state = (aptxbtenc*)_state; + int32_t j = 0; + int32_t k; + int32_t t; + + clearmem(_state, sizeof(aptxbtenc)); + + if (state == 0) + { + return 1; + } + state->m_syncWordPhase = 7L; + + if (endian == 0) + { + state->m_endian = 0; + } + else + { + state->m_endian = 8; + } + + /* default setting should be stereo autosync, + for backwards-compatability with legacy applications that use this library */ + state->m_sync_mode = stereo; + + for (j = 0; j < 2; j++) + { + Encoder_data* encode_dat = &state->m_encoderData[j]; + uint32_t i; + + /* Create a quantiser and subband processor for each subband */ + for (i = LL; i <= HH; i++) + { + encode_dat->m_codewordHistory = 0L; + + encode_dat->m_qdata[i].thresholdTablePtr = subbandParameters[i].threshTable; + encode_dat->m_qdata[i].thresholdTablePtr_sl1 = subbandParameters[i].threshTable_sl1; + encode_dat->m_qdata[i].ditherTablePtr = subbandParameters[i].dithTable; + encode_dat->m_qdata[i].minusLambdaDTable = subbandParameters[i].minusLambdaDTable; + encode_dat->m_qdata[i].codeBits = subbandParameters[i].numBits; + encode_dat->m_qdata[i].qCode = 0L; + encode_dat->m_qdata[i].altQcode = 0L; + encode_dat->m_qdata[i].distPenalty = 0L; + + /* initialisation of inverseQuantiser data */ + encode_dat->m_SubbandData[i].m_iqdata.thresholdTablePtr = subbandParameters[i].threshTable; + encode_dat->m_SubbandData[i].m_iqdata.thresholdTablePtr_sl1 = subbandParameters[i].threshTable_sl1; + encode_dat->m_SubbandData[i].m_iqdata.ditherTablePtr_sf1 = subbandParameters[i].dithTable_sh1; + encode_dat->m_SubbandData[i].m_iqdata.incrTablePtr = subbandParameters[i].incrTable; + encode_dat->m_SubbandData[i].m_iqdata.maxLogDelta = subbandParameters[i].maxLogDelta; + encode_dat->m_SubbandData[i].m_iqdata.minLogDelta = subbandParameters[i].minLogDelta; + encode_dat->m_SubbandData[i].m_iqdata.delta = 0; + encode_dat->m_SubbandData[i].m_iqdata.logDelta = 0; + encode_dat->m_SubbandData[i].m_iqdata.invQ = 0; + encode_dat->m_SubbandData[i].m_iqdata.iquantTableLogPtr = &IQuant_tableLogT[0]; + + // Initializing data for predictor filter + encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.modulo = subbandParameters[i].numZeros; + + for (t = 0; t < 48; t++) + { + encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.buffer[t] = 0; + } + + encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.pointer = 0; + /* Initialise the previous zero filter output and predictor output to zero */ + encode_dat->m_SubbandData[i].m_predData.m_zeroVal = 0L; + encode_dat->m_SubbandData[i].m_predData.m_predVal = 0L; + encode_dat->m_SubbandData[i].m_predData.m_numZeros = subbandParameters[i].numZeros; + /* Initialise the contents of the pole data delay line to zero */ + encode_dat->m_SubbandData[i].m_predData.m_poleDelayLine[0] = 0L; + encode_dat->m_SubbandData[i].m_predData.m_poleDelayLine[1] = 0L; + + for (k = 0; k < 24; k++) + { + encode_dat->m_SubbandData[i].m_ZeroCoeffData.m_zeroCoeff[k] = 0; + } + // Initializing data for zerocoeff update function. + encode_dat->m_SubbandData[i].m_ZeroCoeffData.m_numZeros = subbandParameters[i].numZeros; + + /* Initializing data for PoleCoeff update function. + * Fill the adaptation delay line with +1 initially */ + encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleAdaptDelayLine.s32 = 0x00010001; + + /* Zero the pole coefficients */ + encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleCoeff[0] = 0L; + encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleCoeff[1] = 0L; + } + } + return 0; +} + +APTXBTENCEXPORT int aptxbtenc_setsync_mode(void* _state, int32_t sync_mode) +{ + aptxbtenc* state = (aptxbtenc*)_state; + state->m_sync_mode = sync_mode; + + return 0; +} + +APTXBTENCEXPORT int aptxbtenc_encodestereo(void* _state, void* _pcmL, void* _pcmR, void* _buffer) +{ + aptxbtenc* state = (aptxbtenc*)_state; + int32_t* pcmL = (int32_t*)_pcmL; + int32_t* pcmR = (int32_t*)_pcmR; + int16_t* buffer = (int16_t*)_buffer; + int32_t tmp_reg; + int16_t tmp_out; + //Feed the PCM to the dual aptX encoders + aptxEncode(pcmL, &state->m_qmf_l, &state->m_encoderData[0]); + aptxEncode(pcmR, &state->m_qmf_r, &state->m_encoderData[1]); + + // only insert sync information if we are not in non-autosync mode. + // The Non-autosync mode changes only take effect in the packCodeword() function. + if (state->m_sync_mode != no_sync) + { + if (state->m_sync_mode == stereo) + { + //Insert the autosync information into the stereo quantised codes + xbtEncinsertSync(&state->m_encoderData[0], &state->m_encoderData[1], &state->m_syncWordPhase); + } + else + { + //Insert the autosync information into the two individual mono quantised codes + xbtEncinsertSyncDualMono(&state->m_encoderData[0], &state->m_encoderData[1], &state->m_syncWordPhase); + } + } + + aptxPostEncode(&state->m_encoderData[0]); + aptxPostEncode(&state->m_encoderData[1]); + + //Pack the (possibly adjusted) codes into a 16-bit codeword per channel + tmp_reg = packCodeword(&state->m_encoderData[0], state->m_sync_mode); + // Swap bytes to output data in big-endian as expected by bc5 code... + tmp_out = tmp_reg >> state->m_endian; + tmp_out |= tmp_reg << state->m_endian; + + buffer[0] = (int16_t)tmp_out; + tmp_reg = packCodeword(&state->m_encoderData[1], state->m_sync_mode); + // Swap bytes to output data in big-endian as expected by bc5 code... + tmp_out = tmp_reg >> state->m_endian; + tmp_out |= tmp_reg << state->m_endian; + + buffer[1] = (int16_t)tmp_out; + + return 0; +} diff --git a/system/embdrv/encoder_for_aptx/src/swversion.h b/system/embdrv/encoder_for_aptx/src/swversion.h new file mode 100644 index 00000000000..792b576a8f5 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/src/swversion.h @@ -0,0 +1,8 @@ +#ifndef SWVERSION_H +#define SWVERSION_H + + +const char *swversion = "1.0.0"; + + +#endif //SWVERSION_H diff --git a/system/embdrv/encoder_for_aptxhd/include/aptXHDbtenc.h b/system/embdrv/encoder_for_aptxhd/include/aptXHDbtenc.h new file mode 100644 index 00000000000..bd2bc801c3e --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/include/aptXHDbtenc.h @@ -0,0 +1,49 @@ +/*----------------------------------------------------------------------------- + * + * This file exposes a public interface to allow clients to invoke aptX HD + * encoding on 4 new PCM samples, generating 2 new codeword (one for the + * left channel and one for the right channel). + * + *----------------------------------------------------------------------------*/ + +#ifndef APTXHDBTENC_H +#define APTXHDBTENC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _DLLEXPORT +#define APTXHDBTENCEXPORT __declspec(dllexport) +#else +#define APTXHDBTENCEXPORT +#endif + + +/* SizeofAptxhdbtenc returns the size (in byte) of the memory + * allocation required to store the state of the encoder */ +APTXHDBTENCEXPORT int SizeofAptxhdbtenc (void); + +/* aptxhdbtenc_version can be used to extract the version number + * of the aptX HD encoder */ +APTXHDBTENCEXPORT const char* aptxhdbtenc_version(void); + +/* aptxhdbtenc_init is used to initialise the encoder structure. + * _state should be a pointer to the encoder structure (stereo). + * endian represent the endianness of the output data + * (0=little endian. Big endian otherwise) + * The function returns 1 if an error occurred during the initialisation. + * The function returns 0 if no error occurred during the initialisation. */ +APTXHDBTENCEXPORT int aptxhdbtenc_init(void* _state, short endian); + +/* StereoEncode will take 8 audio samples (24-bit per sample) + * and generate one 24-bit codeword with autosync inserted. + * The bitstream is compatible with be BC05 implementation. */ +APTXHDBTENCEXPORT int aptxhdbtenc_encodestereo(void* _state, void* _pcmL, void* _pcmR, void* _buffer); + + +#ifdef __cplusplus +} // /extern "C" +#endif + +#endif //APTXHDBTENC_H diff --git a/system/embdrv/encoder_for_aptxhd/src/AptxEncoder.h b/system/embdrv/encoder_for_aptxhd/src/AptxEncoder.h new file mode 100644 index 00000000000..bfd5fb4f86a --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/AptxEncoder.h @@ -0,0 +1,87 @@ +/*------------------------------------------------------------------------------ + * + * All declarations relevant for aptxhdEncode. This function allows clients + * to invoke aptX HD encoding on 4 new PCM samples, + * generating 4 new quantised codes. A separate function allows the + * packing of the 4 codes into a 24-bit word. + * + *----------------------------------------------------------------------------*/ + +#ifndef APTXENCODER_H +#define APTXENCODER_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +#include "AptxParameters.h" +#include "DitherGenerator.h" +#include "Quantiser.h" +#include "SubbandFunctionsCommon.h" +#include "Qmf.h" + + +/* Function to carry out a single-channel aptX HD encode on 4 new PCM samples */ +XBT_INLINE_ void aptxhdEncode(int32_t pcm[4], Qmf_storage* Qmf_St, Encoder_data* EncoderDataPt) +{ + int32_t predVals[4]; + int32_t qCodes[4]; + int32_t aqmfOutputs[4]; + + /* Extract the previous predicted values and quantised codes into arrays */ + predVals[0] = EncoderDataPt->m_SubbandData[0].m_predData.m_predVal; + qCodes[0] = EncoderDataPt->m_qdata[0].qCode; + + predVals[1] = EncoderDataPt->m_SubbandData[1].m_predData.m_predVal; + qCodes[1] = EncoderDataPt->m_qdata[1].qCode; + + predVals[2] = EncoderDataPt->m_SubbandData[2].m_predData.m_predVal; + qCodes[2] = EncoderDataPt->m_qdata[2].qCode; + + predVals[3] = EncoderDataPt->m_SubbandData[3].m_predData.m_predVal; + qCodes[3] = EncoderDataPt->m_qdata[3].qCode; + + /* Update codeword history, then generate new dither values. */ + EncoderDataPt->m_codewordHistory = xbtEncupdateCodewordHistory(qCodes, EncoderDataPt->m_codewordHistory); + EncoderDataPt->m_dithSyncRandBit = xbtEncgenerateDither(EncoderDataPt->m_codewordHistory, EncoderDataPt->m_ditherOutputs); + + /* Run the analysis QMF */ + QmfAnalysisFilter(pcm, Qmf_St, predVals, aqmfOutputs); + + /* Run the quantiser for each subband */ + quantiseDifference_HDLL(aqmfOutputs[0], EncoderDataPt->m_ditherOutputs[0], EncoderDataPt->m_SubbandData[0].m_iqdata.delta, &EncoderDataPt->m_qdata[0]); + quantiseDifference_HDLH(aqmfOutputs[1], EncoderDataPt->m_ditherOutputs[1], EncoderDataPt->m_SubbandData[1].m_iqdata.delta, &EncoderDataPt->m_qdata[1]); + quantiseDifference_HDHL(aqmfOutputs[2], EncoderDataPt->m_ditherOutputs[2], EncoderDataPt->m_SubbandData[2].m_iqdata.delta, &EncoderDataPt->m_qdata[2]); + quantiseDifference_HDHH(aqmfOutputs[3], EncoderDataPt->m_ditherOutputs[3], EncoderDataPt->m_SubbandData[3].m_iqdata.delta, &EncoderDataPt->m_qdata[3]); +} + +XBT_INLINE_ void aptxhdPostEncode(Encoder_data* EncoderDataPt) +{ + /* Run the remaining subband processing for each subband */ + /* Manual inlining on the 4 subband */ + processSubband_HDLL(EncoderDataPt->m_qdata[0].qCode, + EncoderDataPt->m_ditherOutputs[0], + &EncoderDataPt->m_SubbandData[0], + &EncoderDataPt->m_SubbandData[0].m_iqdata); + + processSubband_HD(EncoderDataPt->m_qdata[1].qCode, + EncoderDataPt->m_ditherOutputs[1], + &EncoderDataPt->m_SubbandData[1], + &EncoderDataPt->m_SubbandData[1].m_iqdata); + + processSubband_HDHL(EncoderDataPt->m_qdata[2].qCode, + EncoderDataPt->m_ditherOutputs[2], + &EncoderDataPt->m_SubbandData[2], + &EncoderDataPt->m_SubbandData[2].m_iqdata); + + processSubband_HD(EncoderDataPt->m_qdata[3].qCode, + EncoderDataPt->m_ditherOutputs[3], + &EncoderDataPt->m_SubbandData[3], + &EncoderDataPt->m_SubbandData[3].m_iqdata); +} + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //APTXENCODER_H diff --git a/system/embdrv/encoder_for_aptxhd/src/AptxParameters.h b/system/embdrv/encoder_for_aptxhd/src/AptxParameters.h new file mode 100644 index 00000000000..b3e9dd3225d --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/AptxParameters.h @@ -0,0 +1,248 @@ +/*------------------------------------------------------------------------------ + * + * General shared aptX HD parameters. + * + *-----------------------------------------------------------------------------*/ + +#ifndef APTXPARAMETERS_H +#define APTXPARAMETERS_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + +#include <stdint.h> +#include "CBStruct.h" + +#if defined _MSC_VER + #define XBT_INLINE_ inline + #define _STDQMFOUTERCOEFF 1 +#elif defined __clang__ + #define XBT_INLINE_ static inline + #define _STDQMFOUTERCOEFF 1 +#elif defined __GNUC__ + #define XBT_INLINE_ inline + #define _STDQMFOUTERCOEFF 1 +#else + #define XBT_INLINE_ static + #define _STDQMFOUTERCOEFF 1 +#endif + + +/* Signed saturate to a 24bit value */ +XBT_INLINE_ int32_t ssat24(int32_t val) +{ + if (val > 0x7FFFFF) + val = 0x7FFFFF; + if (val < -0x800000) + val = -0x800000; + return val; +} + +typedef union u_reg64 +{ + uint64_t u64; + int64_t s64; + struct s_u32 + { +#ifdef __BIGENDIAN + uint32_t h; + uint32_t l; +#else + uint32_t l; + uint32_t h; +#endif + } u32; + struct s_s32 + { +#ifdef __BIGENDIAN + int32_t h; + int32_t l; +#else + int32_t l; + int32_t h; +#endif + } s32; +} reg64_t; + +typedef union u_reg32 +{ + uint32_t u32; + int32_t s32; + struct s_u16 + { +#ifdef __BIGENDIAN + uint16_t h; + uint16_t l; +#else + uint16_t l; + uint16_t h; +#endif + } u16; + struct s_s16 + { +#ifdef __BIGENDIAN + int16_t h; + int16_t l; +#else + int16_t l; + int16_t h; +#endif + } s16; +} reg32_t; + +/* Each aptX HD enc/dec round consumes/produces 4 PCM samples */ +static const uint32_t numPcmSamples = 4; + +/* Symbolic constants for PCM data indicies. */ +enum +{ + FirstPcm = 0, + SecondPcm = 1, + ThirdPcm = 2, + FourthPcm = 3 +}; + +/* Number of subbands is fixed at 4 */ +#define NUMSUBBANDS 4 + +/* Symbolic constants for subband identification. */ +typedef enum {LL=0, LH=1, HL=2, HH=3} bands; + +/* Structure declaration to bind a set of subband parameters */ +typedef struct +{ + const int32_t* threshTable; + const int32_t* threshTable_sl1; + const int32_t* dithTable; + const int32_t* dithTable_sh1; + const int32_t* minusLambdaDTable; + const int32_t* incrTable; + int32_t numBits; + int32_t maxLogDelta; + int32_t minLogDelta; + int32_t numZeros; +} SubbandParameters; + +/* Struct required for the polecoeffcalculator function of btaptXHD encoder and decoder*/ +/* Size of structure: 16 Bytes */ +typedef struct +{ + /* delay line for previous sgn values */ + reg32_t m_poleAdaptDelayLine; + /* 2 pole filter coeffs */ + int32_t m_poleCoeff[2]; +} PoleCoeff_data; + +/* Struct required for the zerocoeffcalculator function of btaptXHD encoder and decoder*/ +/* Size of structure: 100 Bytes */ +typedef struct +{ + /* The zero filter length for this subband */ + int32_t m_numZeros; + /* Maximum number of zeros for any subband is 24. */ + /* 24 zero filter coeffs */ + int32_t m_zeroCoeff[24]; +} ZeroCoeff_data; + +/* Struct required for the prediction filtering function of btaptXHD encoder and decoder*/ +/* Size of structure: 200+20=220 Bytes */ +typedef struct +{ + /* Number of zeros associated with this subband */ + int32_t m_numZeros; + /* Zero data delay line (circular) */ + circularBuffer m_zeroDelayLine; + /* 2-tap pole data delay line */ + int32_t m_poleDelayLine[2]; + /* Output from zero filter */ + int32_t m_zeroVal; + /* Output from overall ARMA filter */ + int32_t m_predVal; +} Predictor_data; + +/* Struct required for the Quantisation function of btaptXHD encoder and decoder*/ +/* Size of structure: 24 Bytes */ +typedef struct +{ + /* Number of bits in the quantised code for this subband */ + int32_t codeBits; + /* Pointer to threshold table */ + const int32_t* thresholdTablePtr; + const int32_t* thresholdTablePtr_sl1; + + /* Pointer to dither table */ + const int32_t* ditherTablePtr; + /* Pointer to minus Lambda table */ + const int32_t* minusLambdaDTable; + /* Output quantised code */ + int32_t qCode; + /* Alternative quantised code for sync purposes */ + int32_t altQcode; + /* Penalty associated with choosing alternative code */ + int32_t distPenalty; +} Quantiser_data; + +/* Struct required for the inverse Quantisation function of btaptXHD encoder and decoder*/ +/* Size of structure: 32 Bytes */ +typedef struct +{ + /* Pointer to threshold table */ + const int32_t* thresholdTablePtr; + const int32_t* thresholdTablePtr_sl1; + /* Pointer to dither table */ + const int32_t* ditherTablePtr_sf1; + + /* Pointer to increment table */ + const int32_t* incrTablePtr; + /* Upper and lower bounds for logDelta */ + int32_t maxLogDelta; + int32_t minLogDelta; + /* Delta (quantisation step size */ + int32_t delta; + /* Delta, expressed as a log base 2 */ + uint16_t logDelta; + /* Output dequantised signal */ + int32_t invQ; + /* pointer to IQuant_tableLogT */ + const int32_t* iquantTableLogPtr; +} IQuantiser_data; + +/* Subband data structure btaptXHD encoder*/ +/* Size of structure: 116+220+32= 368 Bytes */ +typedef struct +{ + /* Subband processing consists of inverse quantisation, predictor + * coefficient update, and predictor filtering. */ + ZeroCoeff_data m_ZeroCoeffData; + PoleCoeff_data m_PoleCoeffData; + /* structure holding the data associated with the predictor */ + Predictor_data m_predData; + /* iqdata holds the data associated with the instance of inverse quantiser */ + IQuantiser_data m_iqdata; +} Subband_data; + +/* Encoder data structure btaptXHD encoder*/ +/* Size of structure: 368*4+24+4*24 = 1592 Bytes */ +typedef struct +{ + /* Subband processing consists of inverse quantisation, predictor + * coefficient update, and predictor filtering. */ + Subband_data m_SubbandData[4]; + int32_t m_codewordHistory; + int32_t m_dithSyncRandBit; + int32_t m_ditherOutputs[4]; + /* structure holding data values for this quantiser */ + Quantiser_data m_qdata[4]; +} Encoder_data; + +/* Subband-specific number of predcitor zero filter coefficients. */ +static const uint32_t numZeroFilterCoeffs[4] = {24, 12, 6, 12}; + +/* Delta is scaled by 4 positions within the quantiser and inverse quantiser. */ +static const uint32_t deltaScale = 4; + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //APTXPARAMETERS_H diff --git a/system/embdrv/encoder_for_aptxhd/src/AptxTables.h b/system/embdrv/encoder_for_aptxhd/src/AptxTables.h new file mode 100644 index 00000000000..5db25e9b36d --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/AptxTables.h @@ -0,0 +1,1365 @@ +/*------------------------------------------------------------------------------ + * + * All table definitions used for the quantizer. + * + *----------------------------------------------------------------------------*/ + +#ifndef APTXTABLES_H +#define APTXTABLES_H + +#include "AptxParameters.h" + +/* Quantisation threshold, logDelta increment and dither tables for 4-bit codes */ +static const int32_t dq4bit24_sl1[9] = +{ + -95044, + 95044, + 295844, + 528780, + 821332, + 1226438, + 1890540, + 3344850, + 6450664, +}; + +static const int32_t q4incr24[9] = +{ + 0, + -17, + 5, + 30, + 62, + 105, + 177, + 334, + 518, +}; + +static const int32_t dq4dith24_sf1[9] = +{ + 95044, + 95044, + 105754, + 127180, + 165372, + 39736, + 424366, + 1029946, + 2075866, +}; + +static const int32_t dq4mLamb24[8] = +{ + 0, + -2678, + -5357, + -9548, + 31409, + -96158, + -151395, + -261480, +}; + +/* Quantisation threshold, logDelta increment and dither tables for 5-bit codes */ +static const int32_t dq5bit24_sl1[17] = +{ + -45754, + 45754, + 138496, + 234896, + 337336, + 448310, + 570738, + 708380, + 866534, + 1053262, + 1281958, + 1577438, + 1993050, + 2665984, + 3900982, + 5902844, + 8897462, +}; + +static const int32_t q5incr24[17] = +{ + 0, + -18, + -8, + 2, + 13, + 25, + 38, + 53, + 70, + 90, + 115, + 147, + 192, + 264, + 398, + 521, + 521, +}; + +static const int32_t dq5dith24_sf1[17] = +{ + 45754, + 45754, + 46988, + 49412, + 53026, + 57950, + 64478, + 73164, + 84988, + 101740, + 126958, + 168522, + 247092, + 425842, + 809154, + 1192708, + 1801910, +}; + +static const int32_t dq5mLamb24[16] = +{ + 0, + -309, + -606, + -904, + -1231, + -1632, + -2172, + -2956, + -4188, + -6305, + -10391, + -19643, + -44688, + -95828, + -95889, + -152301, +}; + +/* Quantisation threshold, logDelta increment and dither tables for 6-bit codes */ +static const int32_t dq6bit24_sl1[33] = +{ + -21236, + 21236, + 63830, + 106798, + 150386, + 194832, + 240376, + 287258, + 335726, + 386034, + 438460, + 493308, + 550924, + 611696, + 676082, + 744626, + 817986, + 896968, + 982580, + 1076118, + 1179278, + 1294344, + 1424504, + 1574386, + 1751090, + 1966260, + 2240868, + 2617662, + 3196432, + 4176450, + 5658260, + 7671068, + 10380372, +}; + +static const int32_t q6incr24[33] = +{ + 0, + -21, + -16, + -12, + -7, + -2, + 3, + 8, + 13, + 19, + 24, + 30, + 36, + 43, + 50, + 57, + 65, + 74, + 83, + 93, + 104, + 117, + 131, + 147, + 166, + 189, + 219, + 259, + 322, + 427, + 521, + 521, + 521, +}; + +static const int32_t dq6dith24_sf1[33] = +{ + 21236, + 21236, + 21360, + 21608, + 21978, + 22468, + 23076, + 23806, + 24660, + 25648, + 26778, + 28070, + 29544, + 31228, + 33158, + 35386, + 37974, + 41008, + 44606, + 48934, + 54226, + 60840, + 69320, + 80564, + 96140, + 119032, + 155576, + 221218, + 357552, + 622468, + 859344, + 1153464, + 1555840, +}; + +static const int32_t dq6mLamb24[32] = +{ + 0, + -31, + -62, + -93, + -123, + -152, + -183, + -214, + -247, + -283, + -323, + -369, + -421, + -483, + -557, + -647, + -759, + -900, + -1082, + -1323, + -1654, + -2120, + -2811, + -3894, + -5723, + -9136, + -16411, + -34084, + -66229, + -59219, + -73530, + -100594, +}; + +/* Quantisation threshold, logDelta increment and dither tables for 9-bit codes */ +static const int32_t dq9bit24_sl1[257] = +{ + -2436, + 2436, + 7308, + 12180, + 17054, + 21930, + 26806, + 31686, + 36566, + 41450, + 46338, + 51230, + 56124, + 61024, + 65928, + 70836, + 75750, + 80670, + 85598, + 90530, + 95470, + 100418, + 105372, + 110336, + 115308, + 120288, + 125278, + 130276, + 135286, + 140304, + 145334, + 150374, + 155426, + 160490, + 165566, + 170654, + 175756, + 180870, + 185998, + 191138, + 196294, + 201466, + 206650, + 211850, + 217068, + 222300, + 227548, + 232814, + 238096, + 243396, + 248714, + 254050, + 259406, + 264778, + 270172, + 275584, + 281018, + 286470, + 291944, + 297440, + 302956, + 308496, + 314056, + 319640, + 325248, + 330878, + 336532, + 342212, + 347916, + 353644, + 359398, + 365178, + 370986, + 376820, + 382680, + 388568, + 394486, + 400430, + 406404, + 412408, + 418442, + 424506, + 430600, + 436726, + 442884, + 449074, + 455298, + 461554, + 467844, + 474168, + 480528, + 486922, + 493354, + 499820, + 506324, + 512866, + 519446, + 526064, + 532722, + 539420, + 546160, + 552940, + 559760, + 566624, + 573532, + 580482, + 587478, + 594520, + 601606, + 608740, + 615920, + 623148, + 630426, + 637754, + 645132, + 652560, + 660042, + 667576, + 675164, + 682808, + 690506, + 698262, + 706074, + 713946, + 721876, + 729868, + 737920, + 746036, + 754216, + 762460, + 770770, + 779148, + 787594, + 796108, + 804694, + 813354, + 822086, + 830892, + 839774, + 848736, + 857776, + 866896, + 876100, + 885386, + 894758, + 904218, + 913766, + 923406, + 933138, + 942964, + 952886, + 962908, + 973030, + 983254, + 993582, + 1004020, + 1014566, + 1025224, + 1035996, + 1046886, + 1057894, + 1069026, + 1080284, + 1091670, + 1103186, + 1114838, + 1126628, + 1138558, + 1150634, + 1162858, + 1175236, + 1187768, + 1200462, + 1213320, + 1226346, + 1239548, + 1252928, + 1266490, + 1280242, + 1294188, + 1308334, + 1322688, + 1337252, + 1352034, + 1367044, + 1382284, + 1397766, + 1413494, + 1429478, + 1445728, + 1462252, + 1479058, + 1496158, + 1513562, + 1531280, + 1549326, + 1567710, + 1586446, + 1605550, + 1625034, + 1644914, + 1665208, + 1685932, + 1707108, + 1728754, + 1750890, + 1773542, + 1796732, + 1820488, + 1844840, + 1869816, + 1895452, + 1921780, + 1948842, + 1976680, + 2005338, + 2034868, + 2065322, + 2096766, + 2129260, + 2162880, + 2197708, + 2233832, + 2271352, + 2310384, + 2351050, + 2393498, + 2437886, + 2484404, + 2533262, + 2584710, + 2639036, + 2696578, + 2757738, + 2822998, + 2892940, + 2968278, + 3049896, + 3138912, + 3236760, + 3345312, + 3467068, + 3605434, + 3765154, + 3952904, + 4177962, + 4452178, + 4787134, + 5187290, + 5647128, + 6159120, + 6720518, + 7332904, + 8000032, + 8726664, + 9518152, + 10380372, +}; + +static const int32_t q9incr24[257] = +{ + 0, + -22, + -21, + -21, + -20, + -20, + -19, + -19, + -18, + -18, + -17, + -17, + -16, + -16, + -15, + -14, + -14, + -13, + -13, + -12, + -12, + -11, + -11, + -10, + -10, + -9, + -9, + -8, + -7, + -7, + -6, + -6, + -5, + -5, + -4, + -4, + -3, + -3, + -2, + -1, + -1, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 8, + 8, + 9, + 9, + 10, + 11, + 11, + 12, + 12, + 13, + 14, + 14, + 15, + 15, + 16, + 17, + 17, + 18, + 19, + 19, + 20, + 20, + 21, + 22, + 22, + 23, + 24, + 24, + 25, + 26, + 26, + 27, + 28, + 28, + 29, + 30, + 30, + 31, + 32, + 33, + 33, + 34, + 35, + 35, + 36, + 37, + 38, + 38, + 39, + 40, + 41, + 41, + 42, + 43, + 44, + 44, + 45, + 46, + 47, + 48, + 48, + 49, + 50, + 51, + 52, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 89, + 90, + 91, + 92, + 93, + 94, + 96, + 97, + 98, + 99, + 101, + 102, + 103, + 105, + 106, + 107, + 109, + 110, + 112, + 113, + 115, + 116, + 118, + 119, + 121, + 122, + 124, + 125, + 127, + 129, + 130, + 132, + 134, + 136, + 137, + 139, + 141, + 143, + 145, + 147, + 149, + 151, + 153, + 155, + 158, + 160, + 162, + 164, + 167, + 169, + 172, + 174, + 177, + 180, + 182, + 185, + 188, + 191, + 194, + 197, + 201, + 204, + 208, + 211, + 215, + 219, + 223, + 227, + 232, + 236, + 241, + 246, + 251, + 257, + 263, + 269, + 275, + 283, + 290, + 298, + 307, + 317, + 327, + 339, + 352, + 367, + 384, + 404, + 429, + 458, + 494, + 522, + 522, + 522, + 522, + 522, + 522, + 522, + 522, + 522, +}; + +static const int32_t dq9dith24_sf1[257] = +{ + 2436, + 2436, + 2436, + 2436, + 2438, + 2438, + 2438, + 2440, + 2442, + 2442, + 2444, + 2446, + 2448, + 2450, + 2454, + 2456, + 2458, + 2462, + 2464, + 2468, + 2472, + 2476, + 2480, + 2484, + 2488, + 2492, + 2498, + 2502, + 2506, + 2512, + 2518, + 2524, + 2528, + 2534, + 2540, + 2548, + 2554, + 2560, + 2568, + 2574, + 2582, + 2588, + 2596, + 2604, + 2612, + 2620, + 2628, + 2636, + 2646, + 2654, + 2664, + 2672, + 2682, + 2692, + 2702, + 2712, + 2722, + 2732, + 2742, + 2752, + 2764, + 2774, + 2786, + 2798, + 2810, + 2822, + 2834, + 2846, + 2858, + 2870, + 2884, + 2896, + 2910, + 2924, + 2938, + 2952, + 2966, + 2980, + 2994, + 3010, + 3024, + 3040, + 3056, + 3070, + 3086, + 3104, + 3120, + 3136, + 3154, + 3170, + 3188, + 3206, + 3224, + 3242, + 3262, + 3280, + 3300, + 3320, + 3338, + 3360, + 3380, + 3400, + 3422, + 3442, + 3464, + 3486, + 3508, + 3532, + 3554, + 3578, + 3602, + 3626, + 3652, + 3676, + 3702, + 3728, + 3754, + 3780, + 3808, + 3836, + 3864, + 3892, + 3920, + 3950, + 3980, + 4010, + 4042, + 4074, + 4106, + 4138, + 4172, + 4206, + 4240, + 4276, + 4312, + 4348, + 4384, + 4422, + 4460, + 4500, + 4540, + 4580, + 4622, + 4664, + 4708, + 4752, + 4796, + 4842, + 4890, + 4938, + 4986, + 5036, + 5086, + 5138, + 5192, + 5246, + 5300, + 5358, + 5416, + 5474, + 5534, + 5596, + 5660, + 5726, + 5792, + 5860, + 5930, + 6002, + 6074, + 6150, + 6226, + 6306, + 6388, + 6470, + 6556, + 6644, + 6736, + 6828, + 6924, + 7022, + 7124, + 7228, + 7336, + 7448, + 7562, + 7680, + 7802, + 7928, + 8058, + 8192, + 8332, + 8476, + 8624, + 8780, + 8940, + 9106, + 9278, + 9458, + 9644, + 9840, + 10042, + 10252, + 10472, + 10702, + 10942, + 11194, + 11458, + 11734, + 12024, + 12328, + 12648, + 12986, + 13342, + 13720, + 14118, + 14540, + 14990, + 15466, + 15976, + 16520, + 17102, + 17726, + 18398, + 19124, + 19908, + 20760, + 21688, + 22702, + 23816, + 25044, + 26404, + 27922, + 29622, + 31540, + 33720, + 36222, + 39116, + 42502, + 46514, + 51334, + 57218, + 64536, + 73830, + 85890, + 101860, + 123198, + 151020, + 183936, + 216220, + 243618, + 268374, + 293022, + 319362, + 347768, + 378864, + 412626, + 449596, +}; + +static const int32_t dq9mLamb24[256] = +{ + 0, + 0, + 0, + -1, + 0, + 0, + -1, + -1, + 0, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -2, + -1, + -1, + -2, + -2, + -2, + -1, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -2, + -3, + -2, + -3, + -2, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -3, + -4, + -3, + -4, + -4, + -4, + -4, + -4, + -4, + -4, + -4, + -4, + -4, + -4, + -4, + -4, + -5, + -4, + -4, + -5, + -4, + -5, + -5, + -5, + -5, + -5, + -5, + -5, + -5, + -5, + -6, + -5, + -5, + -6, + -5, + -6, + -6, + -6, + -6, + -6, + -6, + -6, + -6, + -7, + -6, + -7, + -7, + -7, + -7, + -7, + -7, + -7, + -7, + -7, + -8, + -8, + -8, + -8, + -8, + -8, + -8, + -9, + -9, + -9, + -9, + -9, + -9, + -9, + -10, + -10, + -10, + -10, + -10, + -11, + -11, + -11, + -11, + -11, + -12, + -12, + -12, + -12, + -13, + -13, + -13, + -14, + -14, + -14, + -15, + -15, + -15, + -15, + -16, + -16, + -17, + -17, + -17, + -18, + -18, + -18, + -19, + -19, + -20, + -21, + -21, + -22, + -22, + -23, + -23, + -24, + -25, + -26, + -26, + -27, + -28, + -29, + -30, + -31, + -32, + -33, + -34, + -35, + -36, + -37, + -39, + -40, + -42, + -43, + -45, + -47, + -49, + -51, + -53, + -55, + -58, + -60, + -63, + -66, + -69, + -73, + -76, + -80, + -85, + -89, + -95, + -100, + -106, + -113, + -119, + -128, + -136, + -146, + -156, + -168, + -182, + -196, + -213, + -232, + -254, + -279, + -307, + -340, + -380, + -425, + -480, + -545, + -626, + -724, + -847, + -1003, + -1205, + -1471, + -1830, + -2324, + -3015, + -3993, + -5335, + -6956, + -8229, + -8071, + -6850, + -6189, + -6162, + -6585, + -7102, + -7774, + -8441, + -9243, +}; + +/* Array of structures containing subband parameters. */ +static const SubbandParameters subbandParameters[NUMSUBBANDS] = +{ + /* LL band */ + { + 0, dq9bit24_sl1, 0, dq9dith24_sf1, dq9mLamb24, q9incr24, 9, (18 * 256) - 1, -20, 24 + }, + + /* LH band */ + { + 0, dq6bit24_sl1, 0, dq6dith24_sf1, dq6mLamb24, q6incr24, 6, (21 * 256) - 1, -23, 12 + }, + + /* HL band */ + { + 0, dq4bit24_sl1, 0, dq4dith24_sf1, dq4mLamb24, q4incr24, 4, (23 * 256) - 1, -25, 6 + }, + + /* HH band */ + { + 0, dq5bit24_sl1, 0, dq5dith24_sf1, dq5mLamb24, q5incr24, 5, (22 * 256) - 1, -24, 12 + } +}; + + +#endif //APTXTABLES_H diff --git a/system/embdrv/encoder_for_aptxhd/src/CBStruct.h b/system/embdrv/encoder_for_aptxhd/src/CBStruct.h new file mode 100644 index 00000000000..95e4d59e488 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/CBStruct.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------------ + * + * Structure required to implement a circular buffer. + * + *-----------------------------------------------------------------------------*/ + +#ifndef CBSTRUCT_H +#define CBSTRUCT_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +typedef struct circularBuffer_t +{ + /* Buffer storage */ + int32_t buffer[48]; + /* Pointer to current buffer location */ + uint32_t pointer; + /* Modulo length of circular buffer */ + uint32_t modulo; +} circularBuffer; + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //CBSTRUCT_H diff --git a/system/embdrv/encoder_for_aptxhd/src/CodewordPacker.h b/system/embdrv/encoder_for_aptxhd/src/CodewordPacker.h new file mode 100644 index 00000000000..67a9efbbbfb --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/CodewordPacker.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------------ + * + * Prototype declaration of the CodewordPacker Function + * + * This functions allows a client to supply an array of 4 quantised codes + * (1 per subband) and obtain a packed version as a 24-bit aptX HD codeword. + * + *----------------------------------------------------------------------------*/ + +#ifndef CODEWORDPACKER_H +#define CODEWORDPACKER_H + + +#include "AptxParameters.h" + + +/* This functions allows a client to supply an array of 4 quantised codes + * (1 per subband) and obtain a packed version as a 24-bit aptX HD codeword. */ +XBT_INLINE_ int32_t packCodeword(Encoder_data* EncoderDataPt) +{ + int32_t syncContribution; + int32_t hhCode; + int32_t codeword; + + /* The per-channel contribution to derive the current sync bit is the XOR of + * the 4 code lsbs and the random dither bit. The SyncInserter engineers it + * such that the XOR of the sync contributions from the left and right + * channel give the actual sync bit value. The per-channel sync bit + * contribution overwrites the HH code lsb in the packed codeword. */ + syncContribution = + (EncoderDataPt->m_qdata[0].qCode ^ + EncoderDataPt->m_qdata[1].qCode ^ + EncoderDataPt->m_qdata[2].qCode ^ + EncoderDataPt->m_qdata[3].qCode ^ + EncoderDataPt->m_dithSyncRandBit) & 0x1; + hhCode = (EncoderDataPt->m_qdata[HH].qCode & 0x1eL) | syncContribution; + + /* Pack the 24-bit codeword with the appropriate number of lsbs from each + * quantised code (LL=9, LH=6, HL=4, HH=5). */ + codeword = + (EncoderDataPt->m_qdata[LL].qCode & 0x1ff) | + ((EncoderDataPt->m_qdata[LH].qCode & 0x3f) << 9) | + ((EncoderDataPt->m_qdata[HL].qCode & 0xf) << 15) | + (hhCode << 19); + + return codeword; +} + + +#endif //CODEWORDPACKER_H diff --git a/system/embdrv/encoder_for_aptxhd/src/DitherGenerator.h b/system/embdrv/encoder_for_aptxhd/src/DitherGenerator.h new file mode 100644 index 00000000000..60fb15d7f80 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/DitherGenerator.h @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------------ + * + * These functions allow clients to update an internal codeword history + * attribute from previously-generated quantised codes, and to generate a new + * pseudo-random dither value per subband from this internal attribute. + * + *----------------------------------------------------------------------------*/ + +#ifndef DITHERGENERATOR_H +#define DITHERGENERATOR_H + + +#include "AptxParameters.h" + + +/* This function updates an internal bit-pool (private variable in DitherGenerator) + * based on bits obtained from previously-encoded or received aptX HD codewords. */ +XBT_INLINE_ int32_t xbtEncupdateCodewordHistory(const int32_t quantisedCodes[4], int32_t m_codewordHistory) +{ + int32_t newBits; + int32_t updatedCodewordHistory; + + const int32_t llMask = 0x3L; + const int32_t lhMask = 0x2L; + const int32_t hlMask = 0x1L; + const uint32_t lhShift = 1; + const uint32_t hlShift = 3; + /* Shift value to left-justify a 24-bit value in a 32-bit signed variable*/ + const uint32_t leftJustifyShift = 8; + const uint32_t numNewBits = 4; + + /* Make a 4-bit vector from particular bits from 3 quantised codes */ + newBits = (quantisedCodes[LL] & llMask) + + ((quantisedCodes[LH] & lhMask) << lhShift) + + ((quantisedCodes[HL] & hlMask) << hlShift); + + /* Add the 4 new bits to the codeword history. Note that this is a 24-bit + * value LEFT-JUSTIFIED in a 32-bit signed variable. Maintaining the history + * as signed is useful in the dither generation process below. */ + updatedCodewordHistory = + (m_codewordHistory << numNewBits) + (newBits << leftJustifyShift); + + return updatedCodewordHistory; +} + +/* Function to generate a dither value for each subband based + * on the current contents of the codewordHistory bit-pool. */ +XBT_INLINE_ int32_t xbtEncgenerateDither(int32_t m_codewordHistory, int32_t* m_ditherOutputs) +{ + int32_t history24b; + int32_t upperAcc, lowerAcc; + int32_t accSum; + int64_t tmp_acc; + int32_t ditherSample; + int32_t m_dithSyncRandBit; + + /* Fixed value to multiply codeword history variable by */ + const uint32_t dithConstMultiplier = 0x4f1bbbL; + /* Shift value to left-justify a 24-bit value in a 32-bit signed variable*/ + const uint32_t leftJustifyShift = 8; + + /* AND mask to retain only the lower 24 bits of a variable */ + const int32_t keepLower24bitsMask = 0xffffffL; + + /* Convert the codeword history to a 24-bit signed value. This can be done + * cheaply with a 8-position right-shift since it is maintained as 24-bits + * value left-justified in a signed 32-bit variable. */ + history24b = m_codewordHistory >> (leftJustifyShift - 1); + + /* Multiply the history by a fixed constant. The constant has already been + * shifted right by 1 position to compensate for the left-shift introduced + * on the product by the fractional multiplier. */ + tmp_acc = ((int64_t)history24b * (int64_t)dithConstMultiplier); + + /* Get the upper and lower 24-bit values from the accumulator, and form + * their sum. */ + upperAcc = ((int32_t)(tmp_acc >> 24)) & 0x00FFFFFFL; + lowerAcc = ((int32_t)tmp_acc) & 0x00FFFFFFL; + accSum = upperAcc + lowerAcc; + + /* The dither sample is the 2 msbs of lowerAcc and the 22 lsbs of accSum */ + ditherSample = ((lowerAcc >> 22) + (accSum << 2)) & keepLower24bitsMask; + + /* The sign bit of 24-bit accSum is saved as a random bit to + * assist in the apt-X sync insertion process. */ + m_dithSyncRandBit = (accSum >> 23) & 0x1; + + /* Successive dither outputs for the 4 subbands are versions of ditherSample + * offset by a further 5-position left shift for each subband. Also apply a + * constant left-shift of 8 to turn the values into signed 24-bit values + * left-justified in the 32-bit ditherOutput variable. */ + m_ditherOutputs[HH] = ditherSample << leftJustifyShift; + m_ditherOutputs[HL] = ditherSample << (5 + leftJustifyShift); + m_ditherOutputs[LH] = ditherSample << (10 + leftJustifyShift); + m_ditherOutputs[LL] = ditherSample << (15 + leftJustifyShift); + + return m_dithSyncRandBit; +} + + +#endif //DITHERGENERATOR_H diff --git a/system/embdrv/encoder_for_aptxhd/src/ProcessSubband.c b/system/embdrv/encoder_for_aptxhd/src/ProcessSubband.c new file mode 100644 index 00000000000..e4de607c382 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/ProcessSubband.c @@ -0,0 +1,43 @@ +#include "AptxParameters.h" +#include "SubbandFunctionsCommon.h" +#include "SubbandFunctions.h" + + +/* This function carries out all subband processing (common to both encode and decode). */ +void processSubband_HD(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt) +{ + /* Inverse quantisation */ + invertQuantisation(qCode, ditherVal, iqDataPt); + + /* Predictor pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, SubbandDataPt->m_predData.m_zeroVal, &SubbandDataPt->m_PoleCoeffData); + + /* Predictor filtering */ + performPredictionFiltering(iqDataPt->invQ, SubbandDataPt); +} + +/* processSubband_HDLL is used for the LL subband only. */ +void processSubband_HDLL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt) +{ + /* Inverse quantisation */ + invertQuantisation(qCode, ditherVal, iqDataPt); + + /* Predictor pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, SubbandDataPt->m_predData.m_zeroVal, &SubbandDataPt->m_PoleCoeffData); + + /* Predictor filtering */ + performPredictionFilteringLL(iqDataPt->invQ, SubbandDataPt); +} + +/* processSubband_HDLL is used for the HL subband only. */ +void processSubband_HDHL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt) +{ + /* Inverse quantisation */ + invertQuantisationHL(qCode, ditherVal, iqDataPt); + + /* Predictor pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, SubbandDataPt->m_predData.m_zeroVal, &SubbandDataPt->m_PoleCoeffData); + + /* Predictor filtering */ + performPredictionFilteringHL(iqDataPt->invQ, SubbandDataPt); +} diff --git a/system/embdrv/encoder_for_aptxhd/src/Qmf.h b/system/embdrv/encoder_for_aptxhd/src/Qmf.h new file mode 100644 index 00000000000..91d91b8d94f --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/Qmf.h @@ -0,0 +1,150 @@ +/*------------------------------------------------------------------------------ + * + * This file includes the coefficient tables or the two convolution function + * It also includes the definition of Qmf_storage and the prototype of all + * necessary functions required to implement the QMF filtering. + * + *----------------------------------------------------------------------------*/ + +#ifndef QMF_H +#define QMF_H + + +#include "AptxParameters.h" + + +typedef struct +{ + int32_t QmfL_buf[32]; + int32_t QmfH_buf[32]; + int32_t QmfLH_buf[32]; + int32_t QmfHL_buf[32]; + int32_t QmfLL_buf[32]; + int32_t QmfHH_buf[32]; + int32_t QmfI_pt; + int32_t QmfO_pt; +} Qmf_storage; + +/* Outer QMF filter for aptX HD is a symmetrical 32-tap filter (16 + * different coefficients). The table defined in QmfConv.c */ +#ifndef _STDQMFOUTERCOEFF +const int32_t Qmf_outerCoeffs[12] = +{ + /* (C(1/30)C(3/28)), C(5/26), C(7/24) */ + 0xFE6302DA, 0xFFFFDA75, 0x0000AA6A, + /* C(9/22), C(11/20), C(13/18), C(15/16) */ + 0xFFFE273E, 0x00041E95, 0xFFF710B5, 0x002AC12E, + /* C(17/14), C(19/12), (C(21/10)C(23/8)) */ + 0x000AA328, 0xFFFD8D1F, 0x211E6BDB, + /* (C(25/6)C(27/4)), (C(29/2)C(31/0)) */ + 0x0DB7D8C5, 0xFC7F02B0 +}; +#else +const int32_t Qmf_outerCoeffs[16] = +{ + 730, -413, -9611, 43626, + -121026, 269973, -585547, 2801966, + 697128, -160481, 27611, 8478, + -10043, 3511, 688, -897 +}; +#endif + +/* Each inner QMF filter for aptX HD is a symmetrical 32-tap filter (16 + * different coefficients) */ +const int32_t Qmf_innerCoeffs[16] = +{ + 1033, -584, -13592, 61697, + -171156, 381799, -828088, 3962579, + 985888, -226954, 39048, 11990, + -14203, 4966, 973, -1268 +}; + +void AsmQmfConvI_HD (const int32_t *p1dl_buffPtr, const int32_t *p2dl_buffPtr, const int32_t *coeffPtr, int32_t* filterOutputs); +void AsmQmfConvO_HD(const int32_t *p1dl_buffPtr, const int32_t *p2dl_buffPtr, const int32_t *coeffPtr, int32_t* convSumDiff); + +XBT_INLINE_ void QmfAnalysisFilter(const int32_t pcm[4], Qmf_storage* Qmf_St, const int32_t* predVals, int32_t* aqmfOutputs) +{ + int32_t convSumDiff[4]; + int32_t filterOutputs[4]; + + int32_t lc_QmfO_pt = (Qmf_St->QmfO_pt); + int32_t lc_QmfI_pt = (Qmf_St->QmfI_pt); + + /* Run the analysis QMF */ + /* Symbolic constants to represent the first and second set out outer filter + * outputs. */ + enum { FirstOuterOutputs = 0, SecondOuterOutputs = 1 }; + + /* Load outer filter phase1 and phase2 delay lines with the first 2 PCM + * samples. Convolve the filter and get the 2 convolution results. */ + Qmf_St->QmfL_buf[lc_QmfO_pt + 16] = pcm[FirstPcm]; + Qmf_St->QmfL_buf[lc_QmfO_pt] = pcm[FirstPcm]; + Qmf_St->QmfH_buf[lc_QmfO_pt + 16] = pcm[SecondPcm]; + Qmf_St->QmfH_buf[lc_QmfO_pt++] = pcm[SecondPcm]; + lc_QmfO_pt &= 0xF; + + AsmQmfConvO_HD(&Qmf_St->QmfL_buf[lc_QmfO_pt + 15], &Qmf_St->QmfH_buf[lc_QmfO_pt], + Qmf_outerCoeffs, &convSumDiff[0]); + + /* Load outer filter phase1 and phase2 delay lines with the second 2 PCM + * samples. Convolve the filter and get the 2 convolution results. */ + Qmf_St->QmfL_buf[lc_QmfO_pt + 16] = pcm[ThirdPcm]; + Qmf_St->QmfL_buf[lc_QmfO_pt] = pcm[ThirdPcm]; + Qmf_St->QmfH_buf[lc_QmfO_pt + 16] = pcm[FourthPcm]; + Qmf_St->QmfH_buf[lc_QmfO_pt++] = pcm[FourthPcm]; + lc_QmfO_pt &= 0xF; + + AsmQmfConvO_HD(&Qmf_St->QmfL_buf[lc_QmfO_pt + 15], &Qmf_St->QmfH_buf[lc_QmfO_pt], + Qmf_outerCoeffs, &convSumDiff[1]); + + /* Load the first inner filter phase1 and phase2 delay lines with the 2 + * convolution sum (low-pass) outer filter outputs. Convolve the filter and + * get the 2 convolution results. The first 2 analysis filter outputs are + * the sum and difference values for the first inner filter convolutions. */ + Qmf_St->QmfLL_buf[lc_QmfI_pt + 16] = convSumDiff[0]; + Qmf_St->QmfLL_buf[lc_QmfI_pt] = convSumDiff[0]; + Qmf_St->QmfLH_buf[lc_QmfI_pt + 16] = convSumDiff[1]; + Qmf_St->QmfLH_buf[lc_QmfI_pt] = convSumDiff[1]; + + AsmQmfConvI_HD(&Qmf_St->QmfLL_buf[lc_QmfI_pt + 16], &Qmf_St->QmfLH_buf[lc_QmfI_pt + 1], + &Qmf_innerCoeffs[0], &filterOutputs[LL]); + + /* Load the second inner filter phase1 and phase2 delay lines with the 2 + * convolution difference (high-pass) outer filter outputs. Convolve the + * filter and get the 2 convolution results. The second 2 analysis filter + * outputs are the sum and difference values for the second inner filter + * convolutions. */ + Qmf_St->QmfHL_buf[lc_QmfI_pt + 16] = convSumDiff[2]; + Qmf_St->QmfHL_buf[lc_QmfI_pt] = convSumDiff[2]; + Qmf_St->QmfHH_buf[lc_QmfI_pt + 16] = convSumDiff[3]; + Qmf_St->QmfHH_buf[lc_QmfI_pt++] = convSumDiff[3]; + lc_QmfI_pt &= 0xF; + + AsmQmfConvI_HD(&Qmf_St->QmfHL_buf[lc_QmfI_pt + 15], &Qmf_St->QmfHH_buf[lc_QmfI_pt], + &Qmf_innerCoeffs[0], &filterOutputs[HL]); + + /* Subtracted the previous predicted value from the filter output on a + * per-subband basis. Ensure these values are saturated, if necessary. + * Manual unrolling */ + aqmfOutputs[LL] = filterOutputs[LL] - predVals[LL]; + if (aqmfOutputs[LL] > 8388607) aqmfOutputs[LL] = 8388607; + if (aqmfOutputs[LL] < -8388608) aqmfOutputs[LL] = -8388608; + + aqmfOutputs[LH] = filterOutputs[LH] - predVals[LH]; + if (aqmfOutputs[LH] > 8388607) aqmfOutputs[LH] = 8388607; + if (aqmfOutputs[LH] < -8388608) aqmfOutputs[LH] = -8388608; + + aqmfOutputs[HL] = filterOutputs[HL] - predVals[HL]; + if (aqmfOutputs[HL] > 8388607) aqmfOutputs[HL] = 8388607; + if (aqmfOutputs[HL] < -8388608) aqmfOutputs[HL] = -8388608; + + aqmfOutputs[HH] = filterOutputs[HH] - predVals[HH]; + if (aqmfOutputs[HH] > 8388607) aqmfOutputs[HH] = 8388607; + if (aqmfOutputs[HH] < -8388608) aqmfOutputs[HH] = -8388608; + + (Qmf_St->QmfO_pt) = lc_QmfO_pt; + (Qmf_St->QmfI_pt) = lc_QmfI_pt; +} + + +#endif //QMF_H diff --git a/system/embdrv/encoder_for_aptxhd/src/QmfConv.c b/system/embdrv/encoder_for_aptxhd/src/QmfConv.c new file mode 100644 index 00000000000..16ab0c8d76c --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/QmfConv.c @@ -0,0 +1,337 @@ +/*------------------------------------------------------------------------------ + * + * This file includes convolution functions required for the Qmf. + * + *----------------------------------------------------------------------------*/ + +#include "AptxParameters.h" + + +void AsmQmfConvO_HD(const int32_t* p1dl_buffPtr, const int32_t* p2dl_buffPtr, const int32_t* coeffPtr, int32_t* convSumDiff) +{ + /* Since all manipulated data are "int16_t" it is possible to + * reduce the number of loads by using int32_t type and manipulating + * pairs of data + */ + + int32_t acc; + // Manual inlining as IAR compiler does not seem to do it itself... + // WARNING: This inlining assumes that m_qmfDelayLineLength == 16 + int32_t tmp_round0; + int64_t local_acc0; + int64_t local_acc1; + + int32_t coeffVal0; + int32_t coeffVal1; + int32_t data0; + int32_t data1; + int32_t data2; + int32_t data3; + int32_t phaseConv[2]; + int32_t convSum; + int32_t convDiff; + + coeffVal0 = (*(coeffPtr)); + coeffVal1 = (*(coeffPtr + 1)); + data0 = (*(p1dl_buffPtr)); + data1 = (*(p2dl_buffPtr)); + data2 = (*(p1dl_buffPtr - 1)); + data3 = (*(p2dl_buffPtr + 1)); + + local_acc0 = ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 = ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 2)); + coeffVal1 = (*(coeffPtr + 3)); + data0 = (*(p1dl_buffPtr - 2)); + data1 = (*(p2dl_buffPtr + 2)); + data2 = (*(p1dl_buffPtr - 3)); + data3 = (*(p2dl_buffPtr + 3)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 4)); + coeffVal1 = (*(coeffPtr + 5)); + data0 = (*(p1dl_buffPtr - 4)); + data1 = (*(p2dl_buffPtr + 4)); + data2 = (*(p1dl_buffPtr - 5)); + data3 = (*(p2dl_buffPtr + 5)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 6)); + coeffVal1 = (*(coeffPtr + 7)); + data0 = (*(p1dl_buffPtr - 6)); + data1 = (*(p2dl_buffPtr + 6)); + data2 = (*(p1dl_buffPtr - 7)); + data3 = (*(p2dl_buffPtr + 7)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 8)); + coeffVal1 = (*(coeffPtr + 9)); + data0 = (*(p1dl_buffPtr - 8)); + data1 = (*(p2dl_buffPtr + 8)); + data2 = (*(p1dl_buffPtr - 9)); + data3 = (*(p2dl_buffPtr + 9)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 10)); + coeffVal1 = (*(coeffPtr + 11)); + data0 = (*(p1dl_buffPtr - 10)); + data1 = (*(p2dl_buffPtr + 10)); + data2 = (*(p1dl_buffPtr - 11)); + data3 = (*(p2dl_buffPtr + 11)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 12)); + coeffVal1 = (*(coeffPtr + 13)); + data0 = (*(p1dl_buffPtr - 12)); + data1 = (*(p2dl_buffPtr + 12)); + data2 = (*(p1dl_buffPtr - 13)); + data3 = (*(p2dl_buffPtr + 13)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + coeffVal0 = (*(coeffPtr + 14)); + coeffVal1 = (*(coeffPtr + 15)); + data0 = (*(p1dl_buffPtr - 14)); + data1 = (*(p2dl_buffPtr + 14)); + data2 = (*(p1dl_buffPtr - 15)); + data3 = (*(p2dl_buffPtr + 15)); + + local_acc0 += ((int64_t)(coeffVal0) * (int64_t)data0); + local_acc1 += ((int64_t)(coeffVal0) * (int64_t)data1); + local_acc0 += ((int64_t)(coeffVal1) * (int64_t)data2); + local_acc1 += ((int64_t)(coeffVal1) * (int64_t)data3); + + tmp_round0 = (int32_t)local_acc0; + + local_acc0 += 0x00400000L; + acc = (int32_t)(local_acc0 >> 23); + + if ((((tmp_round0 << 8) ^ 0x40000000) == 0)) + { + acc--; + } + + if (acc > 8388607) + acc = 8388607; + if (acc < -8388608) + acc = -8388608; + + phaseConv[0] = (int32_t)acc; + + tmp_round0 = (int32_t)local_acc1; + + local_acc1 += 0x00400000L; + acc = (int32_t)(local_acc1 >> 23); + if ((((tmp_round0 << 8) ^ 0x40000000) == 0)) + { + acc--; + } + + if (acc > 8388607) + acc = 8388607; + if (acc < -8388608) + acc = -8388608; + + phaseConv[1] = (int32_t)acc; + + convSum = phaseConv[1] + phaseConv[0]; + if (convSum > 8388607) + convSum = 8388607; + if (convSum < -8388608) + convSum = -8388608; + + convDiff = phaseConv[1] - phaseConv[0]; + if (convDiff > 8388607) + convDiff = 8388607; + if (convDiff < -8388608) + convDiff = -8388608; + + *(convSumDiff) = convSum; + *(convSumDiff + 2) = convDiff; +} + +void AsmQmfConvI_HD(const int32_t* p1dl_buffPtr, const int32_t* p2dl_buffPtr, const int32_t* coeffPtr, int32_t* filterOutputs) +{ + int32_t acc; + // WARNING: This inlining assumes that m_qmfDelayLineLength == 16 + int32_t tmp_round0; + int64_t local_acc0; + int64_t local_acc1; + + int32_t coeffVal0; + int32_t coeffVal1; + int32_t data0; + int32_t data1; + int32_t data2; + int32_t data3; + int32_t phaseConv[2]; + int32_t convSum; + int32_t convDiff; + + coeffVal0 = (*(coeffPtr)); + coeffVal1 = (*(coeffPtr + 1)); + data0 = (*(p1dl_buffPtr)); + data1 = (*(p2dl_buffPtr)); + data2 = (*(p1dl_buffPtr - 1)); + data3 = (*(p2dl_buffPtr + 1)); + + local_acc0 = ((int64_t)(coeffVal0)*data0); + local_acc1 = ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 2)); + coeffVal1 = (*(coeffPtr + 3)); + data0 = (*(p1dl_buffPtr - 2)); + data1 = (*(p2dl_buffPtr + 2)); + data2 = (*(p1dl_buffPtr - 3)); + data3 = (*(p2dl_buffPtr + 3)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 4)); + coeffVal1 = (*(coeffPtr + 5)); + data0 = (*(p1dl_buffPtr - 4)); + data1 = (*(p2dl_buffPtr + 4)); + data2 = (*(p1dl_buffPtr - 5)); + data3 = (*(p2dl_buffPtr + 5)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 6)); + coeffVal1 = (*(coeffPtr + 7)); + data0 = (*(p1dl_buffPtr - 6)); + data1 = (*(p2dl_buffPtr + 6)); + data2 = (*(p1dl_buffPtr - 7)); + data3 = (*(p2dl_buffPtr + 7)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 8)); + coeffVal1 = (*(coeffPtr + 9)); + data0 = (*(p1dl_buffPtr - 8)); + data1 = (*(p2dl_buffPtr + 8)); + data2 = (*(p1dl_buffPtr - 9)); + data3 = (*(p2dl_buffPtr + 9)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 10)); + coeffVal1 = (*(coeffPtr + 11)); + data0 = (*(p1dl_buffPtr - 10)); + data1 = (*(p2dl_buffPtr + 10)); + data2 = (*(p1dl_buffPtr - 11)); + data3 = (*(p2dl_buffPtr + 11)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 12)); + coeffVal1 = (*(coeffPtr + 13)); + data0 = (*(p1dl_buffPtr - 12)); + data1 = (*(p2dl_buffPtr + 12)); + data2 = (*(p1dl_buffPtr - 13)); + data3 = (*(p2dl_buffPtr + 13)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + coeffVal0 = (*(coeffPtr + 14)); + coeffVal1 = (*(coeffPtr + 15)); + data0 = (*(p1dl_buffPtr - 14)); + data1 = (*(p2dl_buffPtr + 14)); + data2 = (*(p1dl_buffPtr - 15)); + data3 = (*(p2dl_buffPtr + 15)); + + local_acc0 += ((int64_t)(coeffVal0)*data0); + local_acc1 += ((int64_t)(coeffVal0)*data1); + local_acc0 += ((int64_t)(coeffVal1)*data2); + local_acc1 += ((int64_t)(coeffVal1)*data3); + + tmp_round0 = (int32_t)local_acc0; + + local_acc0 += 0x00400000L; + acc = (int32_t)(local_acc0 >> 23); + + if ((((tmp_round0 << 8) ^ 0x40000000) == 0)) + { + acc--; + } + + if (acc > 8388607) + acc = 8388607; + if (acc < -8388608) + acc = -8388608; + + phaseConv[0] = (int32_t)acc; + + tmp_round0 = (int32_t)local_acc1; + + local_acc1 += 0x00400000L; + acc = (int32_t)(local_acc1 >> 23); + if ((((tmp_round0 << 8) ^ 0x40000000) == 0)) + { + acc--; + } + + if (acc > 8388607) + acc = 8388607; + if (acc < -8388608) + acc = -8388608; + + phaseConv[1] = (int32_t)acc; + + convSum = phaseConv[1] + phaseConv[0]; + if (convSum > 8388607) convSum = 8388607; + if (convSum < -8388608) convSum = -8388608; + + *(filterOutputs) = convSum; + + convDiff = phaseConv[1] - phaseConv[0]; + if (convDiff > 8388607) convDiff = 8388607; + if (convDiff < -8388608) convDiff = -8388608; + + *(filterOutputs + 1) = convDiff; +} diff --git a/system/embdrv/encoder_for_aptxhd/src/QuantiseDifference.c b/system/embdrv/encoder_for_aptxhd/src/QuantiseDifference.c new file mode 100644 index 00000000000..8b069a52ff3 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/QuantiseDifference.c @@ -0,0 +1,763 @@ +#include "AptxParameters.h" + + +XBT_INLINE_ int32_t BsearchLL(const int32_t absDiffSignalShifted, const int32_t delta, const int32_t* dqbitTablePrt) +{ + int32_t qCode; + reg64_t tmp_acc; + int32_t tmp; + int32_t lc_delta = delta << 8; + + qCode = 0; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[128]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode = 128; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 64]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 64; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 32]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 32; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 16]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 16; + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 8]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 8; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 4]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 4; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 2]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 2; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 1]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode++; + + return (qCode); +} + +XBT_INLINE_ int32_t BsearchHL(const int32_t absDiffSignalShifted, const int32_t delta, const int32_t* dqbitTablePrt) +{ + int32_t qCode; + reg64_t tmp_acc; + int32_t tmp; + int32_t lc_delta = delta << 8; + + /* first iteration */ + qCode = 0; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[4]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode = 4; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 2]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 2; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 1]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode++; + + return (qCode); +} + +XBT_INLINE_ int32_t BsearchHH(const int32_t absDiffSignalShifted, const int32_t delta, const int32_t* dqbitTablePrt) +{ + int32_t qCode; + reg64_t tmp_acc; + int32_t tmp; + int32_t lc_delta = delta << 8; + + qCode = 0; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[8]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode = 8; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 4]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 4; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 2]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 2; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 1]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode++; + + return (qCode); +} + +void quantiseDifference_HDHL(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt) +{ + int32_t absDiffSignal; + int32_t absDiffSignalShifted; + int32_t index; + int32_t dithSquared; + int32_t minusLambdaD; + int32_t acc; + int32_t threshDiff; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL; + int32_t tmp_qCode; + int32_t tmp_altQcode; + uint32_t tmp_round0; + int32_t _delta; + + /* Form the absolute value of the difference signal and maintain a version + * that is right-shifted 4 places for delta scaling. */ + absDiffSignal = -diffSignal; + if (diffSignal >= 0) absDiffSignal = diffSignal; + absDiffSignal = ssat24(absDiffSignal); + absDiffSignalShifted = absDiffSignal >> deltaScale; + + /* Binary search for the quantised code. This search terminates with the + * table index of the LARGEST threshold table value for which + * absDiffSignalShifted >= (delta * threshold) + */ + index = BsearchHL(absDiffSignalShifted, delta, qdata_pt->thresholdTablePtr_sl1); + + /* We actually wanted the SMALLEST magnitude quantised code for which + * absDiffSignalShifted < (delta * threshold) + * i.e. the code with the next highest magnitude than the one we actually + * found. We could add +1 to the code magnitude to do this, but we need to + * subtract 1 from the code magnitude to compensate for the "phantom + * element" at the base of the quantisation table. These two effects cancel + * out, so we leave the value of code alone. However, we need to form code+1 + * to get the proper index into the both the threshold and dither tables, + * since we must skip over the phantom element at the base. */ + qdata_pt->qCode = index; + + /* Square the dither and get the value back from the ALU + * (saturated/rounded). */ + tmp_acc.s64 = ((int64_t)ditherVal * (int64_t)ditherVal); + + acc = tmp_acc.s32.h; + tmp_round0 = (uint32_t)acc << 8; + + acc = (acc >> 6) + 1; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + acc = ssat24(acc); + + dithSquared = acc; + + /* Form the negative difference of the dither values at index and index-1. + * Load the accumulator with this value divided by 2. Ensure saturation is + * applied to the difference calculation. */ + minusLambdaD = qdata_pt->minusLambdaDTable[index]; + + tmp_accL = (1 << 23) - (int32_t)dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = (int32_t)tmp_acc.s32.l << 8; + + acc = (tmp_acc.u32.l >> 22) | (tmp_acc.s32.h << 10); + acc++; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + /* Add the threshold table values at index and index-1 to the accumulated + * value. */ + acc += qdata_pt->thresholdTablePtr_sl1[index + 1] >> 1; + //// worst case value for acc = 0x000d3e08 + 0x43E1DB = 511FE3 + acc += qdata_pt->thresholdTablePtr_sl1[index] >> 1; + //// worst case value for acc = 0x511FE3 + 0x362FEC = 874FCF + + // saturation required + acc = ssat24(acc); + + /* Form the threshold table difference at index and index-1. Ensure + * saturation is applied to the difference calculation. */ + threshDiff = qdata_pt->thresholdTablePtr_sl1[index + 1] - qdata_pt->thresholdTablePtr_sl1[index]; + + /* Based on the sign of the difference signal, either add or subtract the + * threshold table difference from the accumulated value. Recover the final + * accumulated value (saturated/rounded) */ + if (diffSignal < 0) + threshDiff = -threshDiff; + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)threshDiff); + + tmp_reg64.s32.h += acc; + acc = tmp_reg64.s32.h; + + if (tmp_reg64.u32.l >= 0x80000000) + acc++; + tmp_round0 = (tmp_reg64.u32.l >> 1) | (tmp_reg64.s32.h << 31); + + acc = ssat24(acc); + + if (tmp_round0 == 0x40000000L) + acc--; + _delta = -delta << 8; + + acc = acc << 4; + + /* Form (absDiffSignal * 0.125) - (acc * delta), which is the final distance + * signal used to determine if dithering alters the quantised code value or + * not. */ + // worst case value for delta is 0x7d400 + tmp_reg64.s64 = ((int64_t)acc * (int64_t)_delta); + tmp_reg64.s32.h += absDiffSignal; + tmp_round0 = (tmp_reg64.u32.l >> 4) | (tmp_reg64.s32.h << 28); + acc = tmp_reg64.s32.h + (1 << 2); + acc >>= 3; + if (tmp_round0 == 0x40000000L) + { + acc--; + } + + tmp_qCode = qdata_pt->qCode; + tmp_altQcode = tmp_qCode - 1; + /* Check the sign of the distance penalty. Get the sign from the + * full-precision accumulator, as done in the Kalimba code. */ + if (tmp_reg64.s32.h < 0) + { + /* The distance is -ve. The optimum code needs decremented by 1 and the + * alternative code is 1 greater than this. Get the rounded version of the + * -ve distance penalty and negate this (form distance magnitude) before + * writing the value out */ + tmp_qCode = tmp_altQcode; + tmp_altQcode++; + acc = -acc; + } + + qdata_pt->distPenalty = acc; + /* If the difference signal is negative, bitwise invert the code (restores + * sign to the magnitude). */ + if (diffSignal < 0) + { + tmp_qCode = ~tmp_qCode; + tmp_altQcode = ~tmp_altQcode; + } + qdata_pt->altQcode = tmp_altQcode; + qdata_pt->qCode = tmp_qCode; +} + +void quantiseDifference_HDHH(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt) +{ + int32_t absDiffSignal; + int32_t absDiffSignalShifted; + int32_t index; + int32_t dithSquared; + int32_t minusLambdaD; + int32_t acc; + int32_t threshDiff; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL; + int32_t tmp_qCode; + int32_t tmp_altQcode; + uint32_t tmp_round0; + int32_t _delta; + + /* Form the absolute value of the difference signal and maintain a version + * that is right-shifted 4 places for delta scaling. */ + absDiffSignal = -diffSignal; + if (diffSignal >= 0) absDiffSignal = diffSignal; + absDiffSignal = ssat24(absDiffSignal); + absDiffSignalShifted = absDiffSignal >> deltaScale; + + /* Binary search for the quantised code. This search terminates with the + * table index of the LARGEST threshold table value for which + * absDiffSignalShifted >= (delta * threshold) + */ + index = BsearchHH(absDiffSignalShifted, delta, qdata_pt->thresholdTablePtr_sl1); + + /* We actually wanted the SMALLEST magnitude quantised code for which + * absDiffSignalShifted < (delta * threshold) + * i.e. the code with the next highest magnitude than the one we actually + * found. We could add +1 to the code magnitude to do this, but we need to + * subtract 1 from the code magnitude to compensate for the "phantom + * element" at the base of the quantisation table. These two effects cancel + * out, so we leave the value of code alone. However, we need to form code+1 + * to get the proper index into the both the threshold and dither tables, + * since we must skip over the phantom element at the base. */ + qdata_pt->qCode = index; + + /* Square the dither and get the value back from the ALU + * (saturated/rounded). */ + tmp_acc.s64 = ((int64_t)ditherVal * (int64_t)ditherVal); + + acc = tmp_acc.s32.h; + tmp_round0 = (uint32_t)acc << 8; + + acc = (acc >> 6) + 1; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + acc = ssat24(acc); + + dithSquared = acc; + + /* Form the negative difference of the dither values at index and index-1. + * Load the accumulator with this value divided by 2. Ensure saturation is + * applied to the difference calculation. */ + minusLambdaD = qdata_pt->minusLambdaDTable[index]; + + tmp_accL = (1 << 23) - (int32_t)dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = (int32_t)tmp_acc.s32.l << 8; + + acc = (tmp_acc.u32.l >> 22) | (tmp_acc.s32.h << 10); + acc++; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + /* Add the threshold table values at index and index-1 to the accumulated + * value. */ + acc += qdata_pt->thresholdTablePtr_sl1[index + 1] >> 1; + //// worst case value for acc = 0x000d3e08 + 0x43E1DB = 511FE3 + acc += qdata_pt->thresholdTablePtr_sl1[index] >> 1; + //// worst case value for acc = 0x511FE3 + 0x362FEC = 874FCF + + // saturation required + acc = ssat24(acc); + + /* Form the threshold table difference at index and index-1. Ensure + * saturation is applied to the difference calculation. */ + threshDiff = qdata_pt->thresholdTablePtr_sl1[index + 1] - qdata_pt->thresholdTablePtr_sl1[index]; + + /* Based on the sign of the difference signal, either add or subtract the + * threshold table difference from the accumulated value. Recover the final + * accumulated value (saturated/rounded) */ + if (diffSignal < 0) + threshDiff = -threshDiff; + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)threshDiff); + tmp_reg64.s32.h += acc; + acc = tmp_reg64.s32.h; + + if (tmp_reg64.u32.l >= 0x80000000) + acc++; + tmp_round0 = (tmp_reg64.u32.l >> 1) | (tmp_reg64.s32.h << 31); + + acc = ssat24(acc); + + if (tmp_round0 == 0x40000000L) + acc--; + _delta = -delta << 8; + + acc = acc << 4; + + /* Form (absDiffSignal * 0.125) - (acc * delta), which is the final distance + * signal used to determine if dithering alters the quantised code value or + * not. */ + // worst case value for delta is 0x7d400 + tmp_reg64.s64 = ((int64_t)acc * (int64_t)_delta); + tmp_reg64.s32.h += absDiffSignal; + tmp_round0 = (tmp_reg64.u32.l >> 4) | (tmp_reg64.s32.h << 28); + acc = tmp_reg64.s32.h + (1 << 2); + acc >>= 3; + if (tmp_round0 == 0x40000000L) + { + acc--; + } + + tmp_qCode = qdata_pt->qCode; + tmp_altQcode = tmp_qCode - 1; + /* Check the sign of the distance penalty. Get the sign from the + * full-precision accumulator, as done in the Kalimba code. */ + if (tmp_reg64.s32.h < 0) + { + /* The distance is -ve. The optimum code needs decremented by 1 and the + * alternative code is 1 greater than this. Get the rounded version of the + * -ve distance penalty and negate this (form distance magnitude) before + * writing the value out */ + tmp_qCode = tmp_altQcode; + tmp_altQcode++; + acc = -acc; + } + + qdata_pt->distPenalty = acc; + /* If the difference signal is negative, bitwise invert the code (restores + * sign to the magnitude). */ + if (diffSignal < 0) + { + tmp_qCode = ~tmp_qCode; + tmp_altQcode = ~tmp_altQcode; + } + qdata_pt->altQcode = tmp_altQcode; + qdata_pt->qCode = tmp_qCode; +} + +void quantiseDifference_HDLL(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt) +{ + int32_t absDiffSignal; + int32_t absDiffSignalShifted; + int32_t index; + int32_t dithSquared; + int32_t minusLambdaD; + int32_t acc; + int32_t threshDiff; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL; + int32_t tmp_qCode; + int32_t tmp_altQcode; + uint32_t tmp_round0; + int32_t _delta; + + /* Form the absolute value of the difference signal and maintain a version + * that is right-shifted 4 places for delta scaling. */ + absDiffSignal = -diffSignal; + if (diffSignal >= 0) absDiffSignal = diffSignal; + absDiffSignal = ssat24(absDiffSignal); + absDiffSignalShifted = absDiffSignal >> deltaScale; + + /* Binary search for the quantised code. This search terminates with the + * table index of the LARGEST threshold table value for which + * absDiffSignalShifted >= (delta * threshold) + */ + index = 0; + + index = BsearchLL(absDiffSignalShifted, delta, qdata_pt->thresholdTablePtr_sl1); + + /* We actually wanted the SMALLEST magnitude quantised code for which + * absDiffSignalShifted < (delta * threshold) + * i.e. the code with the next highest magnitude than the one we actually + * found. We could add +1 to the code magnitude to do this, but we need to + * subtract 1 from the code magnitude to compensate for the "phantom + * element" at the base of the quantisation table. These two effects cancel + * out, so we leave the value of code alone. However, we need to form code+1 + * to get the proper index into the both the threshold and dither tables, + * since we must skip over the phantom element at the base. */ + qdata_pt->qCode = index; + + /* Square the dither and get the value back from the ALU + * (saturated/rounded). */ + + tmp_acc.s64 = ((int64_t)ditherVal * (int64_t)ditherVal); + + acc = tmp_acc.s32.h; + tmp_round0 = (uint32_t)acc << 8; + + acc = (acc >> 6) + 1; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + acc = ssat24(acc); + + dithSquared = acc; + + /* Form the negative difference of the dither values at index and index-1. + * Load the accumulator with this value divided by 2. Ensure saturation is + * applied to the difference calculation. */ + minusLambdaD = qdata_pt->minusLambdaDTable[index]; + + tmp_accL = (1 << 23) - (int32_t)dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = (int32_t)tmp_acc.s32.l << 8; + + acc = (tmp_acc.u32.l >> 22) | (tmp_acc.s32.h << 10); + acc++; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + + /* Add the threshold table values at index and index-1 to the accumulated + * value. */ + + acc += qdata_pt->thresholdTablePtr_sl1[index + 1] >> 1; + //// worst case value for acc = 0x000d3e08 + 0x43E1DB = 511FE3 + acc += qdata_pt->thresholdTablePtr_sl1[index] >> 1; + //// worst case value for acc = 0x511FE3 + 0x362FEC = 874FCF + // saturation required + acc = ssat24(acc); + + /* Form the threshold table difference at index and index-1. Ensure + * saturation is applied to the difference calculation. */ + threshDiff = qdata_pt->thresholdTablePtr_sl1[index + 1] - qdata_pt->thresholdTablePtr_sl1[index]; + + /* Based on the sign of the difference signal, either add or subtract the + * threshold table difference from the accumulated value. Recover the final + * accumulated value (saturated/rounded) */ + + if (diffSignal < 0) + threshDiff = -threshDiff; + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)threshDiff); + tmp_reg64.s32.h += acc; + acc = tmp_reg64.s32.h; + + if (tmp_reg64.u32.l >= 0x80000000) + acc++; + tmp_round0 = (tmp_reg64.u32.l >> 1) | (tmp_reg64.s32.h << 31); + + acc = ssat24(acc); + + if (tmp_round0 == 0x40000000L) + acc--; + _delta = -delta << 8; + + acc = acc << 4; + + /* Form (absDiffSignal * 0.125) - (acc * delta), which is the final distance + * signal used to determine if dithering alters the quantised code value or + * not. */ + // worst case value for delta is 0x7d400 + + tmp_reg64.s64 = ((int64_t)acc * (int64_t)_delta); + tmp_reg64.s32.h += absDiffSignal; + tmp_round0 = (tmp_reg64.u32.l >> 4) | (tmp_reg64.s32.h << 28); + acc = tmp_reg64.s32.h + (1 << 2); + acc >>= 3; + if (tmp_round0 == 0x40000000L) + { + acc--; + } + + tmp_qCode = qdata_pt->qCode; + tmp_altQcode = tmp_qCode - 1; + /* Check the sign of the distance penalty. Get the sign from the + * full-precision accumulator, as done in the Kalimba code. */ + + if (tmp_reg64.s32.h < 0) + { + /* The distance is -ve. The optimum code needs decremented by 1 and the + * alternative code is 1 greater than this. Get the rounded version of the + * -ve distance penalty and negate this (form distance magnitude) before + * writing the value out */ + tmp_qCode = tmp_altQcode; + tmp_altQcode++; + acc = -acc; + } + + qdata_pt->distPenalty = acc; + /* If the difference signal is negative, bitwise invert the code (restores + * sign to the magnitude). */ + if (diffSignal < 0) + { + tmp_qCode = ~tmp_qCode; + tmp_altQcode = ~tmp_altQcode; + } + qdata_pt->altQcode = tmp_altQcode; + qdata_pt->qCode = tmp_qCode; +} + + +int32_t BsearchLH(const int32_t absDiffSignalShifted, const int32_t delta, const int32_t* dqbitTablePrt) +{ + int32_t qCode; + reg64_t tmp_acc; + int32_t tmp; + int32_t lc_delta = delta << 8; + + qCode = 0; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[16]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode = 16; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 8]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 8; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 4]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 4; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 2]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode += 2; + + tmp_acc.s64 = (int64_t)lc_delta * (int64_t)dqbitTablePrt[qCode + 1]; + tmp_acc.s32.h -= absDiffSignalShifted; + tmp = tmp_acc.s32.h | (tmp_acc.u32.l >> 1); + if (tmp <= 0) qCode++; + + return (qCode); +} + + +void quantiseDifference_HDLH(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt) +{ + int32_t absDiffSignal; + int32_t absDiffSignalShifted; + int32_t index; + int32_t dithSquared; + int32_t minusLambdaD; + int32_t acc; + int32_t threshDiff; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL; + int32_t tmp_qCode; + int32_t tmp_altQcode; + + uint32_t tmp_round0; + int32_t _delta; + + /* Form the absolute value of the difference signal and maintain a version + * that is right-shifted 4 places for delta scaling. */ + absDiffSignal = -diffSignal; + if (diffSignal >= 0) absDiffSignal = diffSignal; + absDiffSignal = ssat24(absDiffSignal); + absDiffSignalShifted = absDiffSignal >> deltaScale; + + /* Binary search for the quantised code. This search terminates with the + * table index of the LARGEST threshold table value for which + * absDiffSignalShifted >= (delta * threshold) + */ + + /* first iteration */ + index = BsearchLH(absDiffSignalShifted, delta, qdata_pt->thresholdTablePtr_sl1); + + /* We actually wanted the SMALLEST magnitude quantised code for which + * absDiffSignalShifted < (delta * threshold) + * i.e. the code with the next highest magnitude than the one we actually + * found. We could add +1 to the code magnitude to do this, but we need to + * subtract 1 from the code magnitude to compensate for the "phantom + * element" at the base of the quantisation table. These two effects cancel + * out, so we leave the value of code alone. However, we need to form code+1 + * to get the proper index into the both the threshold and dither tables, + * since we must skip over the phantom element at the base. */ + qdata_pt->qCode = index; + + /* Square the dither and get the value back from the ALU + * (saturated/rounded). */ + + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)ditherVal); + + acc = tmp_reg64.s32.h; + + tmp_round0 = (uint32_t)acc << 8; + + acc = (acc >> 6) + 1; + acc >>= 1; + if (tmp_round0 == 0x40000000L) + acc--; + acc = ssat24(acc); + + dithSquared = acc; + + /* Form the negative difference of the dither values at index and index-1. + * Load the accumulator with this value divided by 2. Ensure saturation is + * applied to the difference calculation. */ + + minusLambdaD = qdata_pt->minusLambdaDTable[index]; + + tmp_accL = (1 << 23) - (int32_t)dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = (int32_t)tmp_acc.s32.l << 8; + + acc = (tmp_acc.u32.l >> 22) | (tmp_acc.s32.h << 10); + if (tmp_round0 == 0x40000000L) + acc -= 2; + acc++; + + /* Add the threshold table values at index and index-1 to the accumulated + * value. */ + + acc += qdata_pt->thresholdTablePtr_sl1[index + 1]; + //// worst case value for acc = 0x000d3e08 + 0x43E1DB = 511FE3 + acc += qdata_pt->thresholdTablePtr_sl1[index]; + acc >>= 1; + + // saturation required + acc = ssat24(acc); + + /* Form the threshold table difference at index and index-1. Ensure + * saturation is applied to the difference calculation. */ + threshDiff = qdata_pt->thresholdTablePtr_sl1[index + 1] - qdata_pt->thresholdTablePtr_sl1[index]; + + /* Based on the sign of the difference signal, either add or subtract the + * threshold table difference from the accumulated value. Recover the final + * accumulated value (saturated/rounded) */ + + if (diffSignal < 0) + threshDiff = -threshDiff; + tmp_reg64.s64 = ((int64_t)ditherVal * (int64_t)threshDiff); + + tmp_reg64.s32.h += acc; + acc = tmp_reg64.s32.h; + + if (tmp_reg64.u32.l >= 0x80000000) + acc++; + tmp_round0 = (tmp_reg64.u32.l >> 1) | (tmp_reg64.s32.h << 31); + + acc = ssat24(acc); + + if (tmp_round0 == 0x40000000L) + acc--; + _delta = -delta << 8; + + acc = acc << 4; + + /* Form (absDiffSignal * 0.125) - (acc * delta), which is the final distance + * signal used to determine if dithering alters the quantised code value or + * not. */ + // worst case value for delta is 0x7d400 + + tmp_reg64.s64 = ((int64_t)acc * (int64_t)_delta); + tmp_reg64.s32.h += absDiffSignal; + tmp_round0 = (tmp_reg64.u32.l >> 4) | (tmp_reg64.s32.h << 28); + acc = tmp_reg64.s32.h + (1 << 2); + acc >>= 3; + if (tmp_round0 == 0x40000000L) + { + acc--; + } + + tmp_qCode = qdata_pt->qCode; + tmp_altQcode = tmp_qCode - 1; + /* Check the sign of the distance penalty. Get the sign from the + * full-precision accumulator, as done in the Kalimba code. */ + + if (tmp_reg64.s32.h < 0) + { + /* The distance is -ve. The optimum code needs decremented by 1 and the + * alternative code is 1 greater than this. Get the rounded version of the + * -ve distance penalty and negate this (form distance magnitude) before + * writing the value out */ + tmp_qCode = tmp_altQcode; + tmp_altQcode++; + acc = -acc; + } + + qdata_pt->distPenalty = acc; + /* If the difference signal is negative, bitwise invert the code (restores + * sign to the magnitude). */ + if (diffSignal < 0) + { + tmp_qCode = ~tmp_qCode; + tmp_altQcode = ~tmp_altQcode; + } + qdata_pt->altQcode = tmp_altQcode; + qdata_pt->qCode = tmp_qCode; +} diff --git a/system/embdrv/encoder_for_aptxhd/src/Quantiser.h b/system/embdrv/encoder_for_aptxhd/src/Quantiser.h new file mode 100644 index 00000000000..e08fec47683 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/Quantiser.h @@ -0,0 +1,27 @@ +/*------------------------------------------------------------------------------ + * + * Function to calculate a quantised representation of an input + * difference signal, based on additional dither values and step-size inputs. + * + *-----------------------------------------------------------------------------*/ + +#ifndef QUANTISER_H +#define QUANTISER_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +#include "AptxParameters.h" + + +void quantiseDifference_HDLL(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt); +void quantiseDifference_HDHL(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt); +void quantiseDifference_HDLH(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_pt); +void quantiseDifference_HDHH(const int32_t diffSignal, const int32_t ditherVal, const int32_t delta, Quantiser_data* qdata_p); + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //QUANTISER_H diff --git a/system/embdrv/encoder_for_aptxhd/src/SubbandFunctions.h b/system/embdrv/encoder_for_aptxhd/src/SubbandFunctions.h new file mode 100644 index 00000000000..84cd2dd42dd --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/SubbandFunctions.h @@ -0,0 +1,183 @@ +/*------------------------------------------------------------------------------ + * + * Subband processing consists of: + * inverse quantisation (defined in a separate file), + * predictor coefficient update (Pole and Zero Coeff update), + * predictor filtering. + * + *----------------------------------------------------------------------------*/ + +#ifndef SUBBANDFUNCTIONS_H +#define SUBBANDFUNCTIONS_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +#include "AptxParameters.h" + + +XBT_INLINE_ void updatePredictorPoleCoefficients(const int32_t invQ, const int32_t prevZfiltOutput, PoleCoeff_data* PoleCoeffDataPt) +{ + int32_t adaptSum; + int32_t sgnP[3]; + int32_t newCoeffs[2]; + int32_t Bacc; + int32_t acc; + int32_t acc2; + int32_t tmp3_round0; + int16_t tmp2_round0; + int16_t tmp_round0; + /* Various constants in various Q formats */ + const int32_t oneQ22 = 4194304L; + const int32_t minusOneQ22 = -4194304L; + const int32_t pointFiveQ21 = 1048576L; + const int32_t minusPointFiveQ21 = -1048576L; + const int32_t pointSevenFiveQ22 = 3145728L; + const int32_t minusPointSevenFiveQ22 = -3145728L; + const int32_t oneMinusTwoPowerMinusFourQ22 = 3932160L; + + /* Symbolic indicies for the pole coefficient arrays. Here we are using a1 + * to represent the first pole filter coefficient and a2 the second. This + * seems to be common ADPCM terminology. */ + enum { a1 = 0, a2 = 1 }; + + /* Symbolic indicies for the sgn array (k, k-1 and k-2 respectively) */ + enum { k = 0, k_1 = 1, k_2 = 2 }; + + /* Form the sum of the inverse quantiser and previous zero filter values */ + adaptSum = invQ + prevZfiltOutput; + adaptSum = ssat24(adaptSum); + + /* Form the sgn of the sum just formed (note +1 and -1 are Q22) */ + if (adaptSum < 0L) + { + sgnP[k] = minusOneQ22; + sgnP[k_1] = -(((int32_t)PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l) << 22); + sgnP[k_2] = -(((int32_t)PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h) << 22); + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h = PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l = -1; + } + if (adaptSum == 0L) + { + sgnP[k] = 0L; + sgnP[k_1] = 0L; + sgnP[k_2] = 0L; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h = PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l = 1; + } + if (adaptSum > 0L) + { + sgnP[k] = oneQ22; + sgnP[k_1] = ((int32_t)PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l) << 22; + sgnP[k_2] = ((int32_t)PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h) << 22; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.h = PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l; + PoleCoeffDataPt->m_poleAdaptDelayLine.s16.l = 1; + } + + /* Clear the accumulator and form -a1(k) * sgn(p(k))sgn(p(k-1)) in Q21. Clip + * it to +/- 0.5 (Q21) so that we can take f(a1) = 4 * a1. This is a partial + * result for the new a2 */ + acc = 0; + acc -= PoleCoeffDataPt->m_poleCoeff[a1] * (sgnP[k_1] >> 22); + + tmp3_round0 = acc & 0x3L; + + acc += 0x001; + acc >>= 1; + if (tmp3_round0 == 0x001L) + { + acc--; + } + + newCoeffs[a2] = acc; + + if (newCoeffs[a2] < minusPointFiveQ21) + { + newCoeffs[a2] = minusPointFiveQ21; + } + if (newCoeffs[a2] > pointFiveQ21) + { + newCoeffs[a2] = pointFiveQ21; + } + + /* Load the accumulator with sgn(p(k))sgn(p(k-2)) right-shifted by 3. The + * 3-position shift is to multiply it by 0.25 and convert from Q22 to Q21. */ + Bacc = (sgnP[k_2] >> 3); + /* Add the current a2 update value to the accumulator (Q21) */ + Bacc += newCoeffs[a2]; + /* Shift the accumulator right by 4 positions. + * Right 7 places to multiply by 2^(-7) + * Left 2 places to scale by 4 (0.25A + B -> A + 4B) + * Left 1 place to convert from Q21 to Q22 */ + Bacc >>= 4; + /* Add a2(k-1) * (1 - 2^(-7)) to the accumulator. Note that the constant is + * expressed as Q23, hence the product is Q22. Get the accumulator value + * back out. */ + acc2 = PoleCoeffDataPt->m_poleCoeff[a2] << 8; + acc2 -= PoleCoeffDataPt->m_poleCoeff[a2] << 1; + Bacc <<= 8; + Bacc += acc2; + + tmp2_round0 = (int16_t)Bacc & 0x01FFL; + + Bacc += 0x0080L; + Bacc >>= 8; + + if (tmp2_round0 == 0x0080L) + { + Bacc--; + } + + newCoeffs[a2] = Bacc; + + /* Clip the new a2(k) value to +/- 0.75 (Q22) */ + if (newCoeffs[a2] < minusPointSevenFiveQ22) + { + newCoeffs[a2] = minusPointSevenFiveQ22; + } + if (newCoeffs[a2] > pointSevenFiveQ22) + { + newCoeffs[a2] = pointSevenFiveQ22; + } + PoleCoeffDataPt->m_poleCoeff[a2] = newCoeffs[a2]; + + /* Form sgn(p(k))sgn(p(k-1)) * (3 * 2^(-8)). The constant is Q23, hence the + * product is Q22. */ + /* Add a1(k-1) * (1 - 2^(-8)) to the accumulator. The constant is Q23, hence + * the product is Q22. Get the value from the accumulator. */ + acc2 = PoleCoeffDataPt->m_poleCoeff[a1] << 8; + acc2 -= PoleCoeffDataPt->m_poleCoeff[a1]; + acc2 += (sgnP[k_1] << 2); + acc2 -= (sgnP[k_1]); + + tmp_round0 = (int16_t)acc2 & 0x01FF; + + acc2 += 0x0080; + acc = (acc2 >> 8); + if (tmp_round0 == 0x0080) + { + acc--; + } + + newCoeffs[a1] = (int32_t)acc; + + /* Clip the new value of a1(k) to +/- (1 - 2^4 - a2(k)). The constant 1 - + * 2^4 is expressed in Q22 format (as is a1 and a2) */ + if (newCoeffs[a1] < (newCoeffs[a2] - oneMinusTwoPowerMinusFourQ22)) + { + newCoeffs[a1] = newCoeffs[a2] - oneMinusTwoPowerMinusFourQ22; + } + if (newCoeffs[a1] > (oneMinusTwoPowerMinusFourQ22 - newCoeffs[a2])) + { + newCoeffs[a1] = oneMinusTwoPowerMinusFourQ22 - newCoeffs[a2]; + } + + PoleCoeffDataPt->m_poleCoeff[a1] = newCoeffs[a1]; +} + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //SUBBANDFUNCTIONS_H diff --git a/system/embdrv/encoder_for_aptxhd/src/SubbandFunctionsCommon.h b/system/embdrv/encoder_for_aptxhd/src/SubbandFunctionsCommon.h new file mode 100644 index 00000000000..618d4399197 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/SubbandFunctionsCommon.h @@ -0,0 +1,520 @@ +/*------------------------------------------------------------------------------ + * + * Subband processing consists of: + * inverse quantisation (defined in a separate file), + * predictor coefficient update (Pole and Zero Coeff update), + * predictor filtering. + * + *----------------------------------------------------------------------------*/ + +#ifndef SUBBANDFUNCTIONSCOMMON_H +#define SUBBANDFUNCTIONSCOMMON_H + + +enum reg64_reg +{ + reg64_H = 1, + reg64_L = 0 +}; + +void processSubband_HD(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt); +void processSubband_HDLL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt); +void processSubband_HDHL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt, IQuantiser_data* iqDataPt); + +/* Function to carry out inverse quantisation for a subband */ +XBT_INLINE_ void invertQuantisation(const int32_t qCode, const int32_t ditherVal, IQuantiser_data* iqdata_pt) +{ + int32_t invQ; + int32_t index; + int32_t acc; + reg64_t tmp_r64; + int64_t tmp_acc; + int32_t tmp_accL; + int32_t tmp_accH; + uint32_t tmp_round0; + uint32_t tmp_round1; + unsigned u16t; + /* log delta leak value (Q23) */ + const uint32_t logDeltaLeakVal = 0x7F6CL; + + /* Turn the quantised code back into an index into the threshold table. This + * involves bitwise inversion of the code (if -ve) and adding 1 (phantom + * element at table base). Then set invQ to be +/- the threshold value, + * depending on the code sign. */ + index = qCode; + if (qCode < 0) + index = (~index); + index = index + 1; + invQ = iqdata_pt->thresholdTablePtr_sl1[index]; + if (qCode < 0) + invQ = -invQ; + + /* Load invQ into the accumulator. Add the product of the dither value times + * the indexed dither table value. Then get the result back from the + * accumulator as an updated invQ. */ + tmp_r64.s64 = ((int64_t)ditherVal * iqdata_pt->ditherTablePtr_sf1[index]); + tmp_r64.s32.h += invQ >> 1; + + acc = tmp_r64.s32.h; + + tmp_round1 = tmp_r64.s32.h & 0x00000001L; + if (tmp_r64.u32.l >= 0x80000000) + acc++; + if (tmp_round1 == 0 && tmp_r64.s32.l == (int32_t)0x80000000L) + acc--; + acc = ssat24(acc); + + invQ = (int32_t)acc; + + /* Scale invQ by the current delta value. Left-shift the result (in the + * accumulator) by 4 positions for the delta scaling. Get the updated invQ + * back from the accumulator. */ + u16t = iqdata_pt->logDelta; + tmp_acc = ((int64_t)invQ * iqdata_pt->delta); + tmp_accL = u16t * logDeltaLeakVal; + tmp_accH = iqdata_pt->incrTablePtr[index]; + acc = (int32_t)(tmp_acc >> (23 - deltaScale)); + invQ = ssat24(acc); + + /* Now update the value of logDelta. Load the accumulator with the index + * value of the logDelta increment table. Add the product of the current + * logDelta scaled by a leaky coefficient (16310 in Q14). Get the value back + * from the accumulator. */ + tmp_accH += tmp_accL >> (32 - 17); + + acc = tmp_accH; + + tmp_r64.u32.l = ((uint32_t)tmp_accL << 17); + tmp_r64.s32.h = tmp_accH; + + tmp_round0 = tmp_r64.u32.l; + tmp_round1 = (int32_t)(tmp_r64.u64 >> 1); + if (tmp_round0 >= 0x80000000L) + acc++; + if (tmp_round1 == 0x40000000L) + acc--; + + /* Limit the updated logDelta between 0 and its subband-specific maximum. */ + if (acc < 0) + acc = 0; + if (acc > iqdata_pt->maxLogDelta) + acc = iqdata_pt->maxLogDelta; + + iqdata_pt->logDelta = (uint16_t)acc; + + /* The updated value of delta is the logTable output (indexed by 5 bits from + * the updated logDelta) shifted by a value involving the logDelta minimum + * and the updated logDelta itself. */ + iqdata_pt->delta = iqdata_pt->iquantTableLogPtr[(acc >> 3) & 0x1f] >> + (22 - 25 - iqdata_pt->minLogDelta - (acc >> 8)); + + iqdata_pt->invQ = invQ; +} + +XBT_INLINE_ void invertQuantisationHL(const int32_t qCode, const int32_t ditherVal, IQuantiser_data* iqdata_pt) +{ + int32_t invQ; + int32_t index; + int32_t acc; + reg64_t tmp_r64; + int64_t tmp_acc; + int32_t tmp_accL; + int32_t tmp_accH; + uint32_t tmp_round0; + uint32_t tmp_round1; + unsigned u16t; + /* log delta leak value (Q23) */ + const uint32_t logDeltaLeakVal = 0x7F6CL; + + /* Turn the quantised code back into an index into the threshold table. This + * involves bitwise inversion of the code (if -ve) and adding 1 (phantom + * element at table base). Then set invQ to be +/- the threshold value, + * depending on the code sign. */ + index = qCode; + if (qCode < 0) + index = (~index); + index = index + 1; + invQ = iqdata_pt->thresholdTablePtr_sl1[index]; + if (qCode < 0) + invQ = -invQ; + + /* Load invQ into the accumulator. Add the product of the dither value times + * the indexed dither table value. Then get the result back from the + * accumulator as an updated invQ. */ + tmp_r64.s64 = ((int64_t)ditherVal * iqdata_pt->ditherTablePtr_sf1[index]); + tmp_r64.s32.h += invQ >> 1; + + acc = tmp_r64.s32.h; + + tmp_round1 = tmp_r64.s32.h & 0x00000001L; + if (tmp_r64.u32.l >= 0x80000000) + acc++; + if (tmp_round1 == 0 && tmp_r64.u32.l == 0x80000000L) + acc--; + acc = ssat24(acc); + + invQ = (int32_t)acc; + + /* Scale invQ by the current delta value. Left-shift the result (in the + * accumulator) by 4 positions for the delta scaling. Get the updated invQ + * back from the accumulator. */ + u16t = iqdata_pt->logDelta; + tmp_acc = ((int64_t)invQ * iqdata_pt->delta); + tmp_accL = u16t * logDeltaLeakVal; + tmp_accH = iqdata_pt->incrTablePtr[index]; + acc = (int32_t)(tmp_acc >> (23 - deltaScale)); + invQ = ssat24(acc); + + /* Now update the value of logDelta. Load the accumulator with the index + * value of the logDelta increment table. Add the product of the current + * logDelta scaled by a leaky coefficient (16310 in Q14). Get the value back + * from the accumulator. */ + tmp_accH += tmp_accL >> (32 - 17); + + acc = tmp_accH; + + tmp_r64.u32.l = ((uint32_t)tmp_accL << 17); + tmp_r64.s32.h = tmp_accH; + + tmp_round0 = tmp_r64.u32.l; + tmp_round1 = (int32_t)(tmp_r64.u64 >> 1); + if (tmp_round0 >= 0x80000000L) + acc++; + if (tmp_round1 == 0x40000000L) + acc--; + + /* Limit the updated logDelta between 0 and its subband-specific maximum. */ + if (acc < 0) + acc = 0; + if (acc > iqdata_pt->maxLogDelta) + acc = iqdata_pt->maxLogDelta; + + iqdata_pt->logDelta = (uint16_t)acc; + + /* The updated value of delta is the logTable output (indexed by 5 bits from + * the updated logDelta) shifted by a value involving the logDelta minimum + * and the updated logDelta itself. */ + iqdata_pt->delta = iqdata_pt->iquantTableLogPtr[(acc >> 3) & 0x1f] >> + (22 - 25 - iqdata_pt->minLogDelta - (acc >> 8)); + + iqdata_pt->invQ = invQ; +} + +/* Function to carry out prediction ARMA filtering for the current subband + * performPredictionFiltering should only be used for HH and LH subband! */ +XBT_INLINE_ void performPredictionFiltering(const int32_t invQ, Subband_data* SubbandDataPt) +{ + int32_t poleVal; + int32_t acc; + int64_t accL; + uint32_t pointer; + int32_t poleDelayLine; + int32_t predVal; + int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff; + int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff; + int32_t* cbuf_pt; + int32_t invQincr_pos; + int32_t invQincr_neg; + int32_t k; + int32_t oldZData; + /* Pole coefficient and data indicies */ + enum { a1 = 0, a2 = 1 }; + + /* Write the newest pole input sample to the pole delay line. + * Ensure the sum of the current dequantised error and the previous + * predictor output is saturated if necessary. */ + poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal; + + poleDelayLine = ssat24(poleDelayLine); + + /* Pole filter convolution. Shift convolution result 1 place to the left + * before retrieving it, since the pole coefficients are Q22 (data is Q23) + * and we want a Q23 result */ + accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]); + /* Update the pole delay line for the next pass by writing the new input + * sample into the 2nd element */ + SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine; + accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine); + poleVal = (int32_t)(accL >> 22); + poleVal = ssat24(poleVal); + + /* Create (2^(-7)) * sgn(invQ) in Q22 format. */ + if (invQ == 0) + { + invQincr_pos = 0L; + } + else + { + invQincr_pos = 0x800000; + } + if (invQ < 0L) + { + invQincr_pos = -invQincr_pos; + } + + invQincr_neg = 0x0080 - invQincr_pos; + invQincr_pos += 0x0080; + + pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 12; + cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer]; + /* partial manual unrolling to improve performance */ + if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 12) + SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0; + + SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ; + + /* Iterate over the number of coefficients for this subband */ + oldZData = invQ; + accL = 0; + for (k = 0; k < 12; k++) + { + uint32_t tmp_round0; + int32_t coeffValue; + int32_t zData0; + + /* ------------------------------------------------------------------*/ + zData0 = (*(cbuf_pt--)); + coeffValue = *(zeroCoeffPt + k); + if (zData0 < 0L) + { + acc = invQincr_neg - coeffValue; + } + else + { + acc = invQincr_pos - coeffValue; + } + tmp_round0 = acc; + acc = (acc >> 8) + coeffValue; + if (((tmp_round0 << 23) ^ 0x80000000) == 0) acc--; + accL += (int64_t)acc * (int64_t)(oldZData); + oldZData = zData0; + *(zeroCoeffPt + k) = acc; + } + + acc = (int32_t)(accL >> 22); + acc = ssat24(acc); + + /* Predictor output is the sum of the pole and zero filter outputs. Ensure + * this is saturated, if necessary. */ + predVal = acc + poleVal; + predVal = ssat24(predVal); + SubbandDataPt->m_predData.m_zeroVal = acc; + SubbandDataPt->m_predData.m_predVal = predVal; + + /* Update the zero filter delay line by writing the new input sample to the + * circular buffer. */ + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 12] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; +} + +XBT_INLINE_ void performPredictionFilteringLL(const int32_t invQ, Subband_data* SubbandDataPt) +{ + int32_t poleVal; + int32_t acc; + int64_t accL; + uint32_t pointer; + int32_t poleDelayLine; + int32_t predVal; + int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff; + int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff; + int32_t* cbuf_pt; + int32_t invQincr_pos; + int32_t invQincr_neg; + int32_t k; + int32_t oldZData; + /* Pole coefficient and data indicies */ + enum { a1 = 0, a2 = 1 }; + + /* Write the newest pole input sample to the pole delay line. + * Ensure the sum of the current dequantised error and the previous + * predictor output is saturated if necessary. */ + poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal; + + poleDelayLine = ssat24(poleDelayLine); + + /* Pole filter convolution. Shift convolution result 1 place to the left + * before retrieving it, since the pole coefficients are Q22 (data is Q23) + * and we want a Q23 result */ + accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]); + /* Update the pole delay line for the next pass by writing the new input + * sample into the 2nd element */ + SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine; + accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine); + poleVal = (int32_t)(accL >> 22); + poleVal = ssat24(poleVal); + /* store poleVal to free one register. */ + SubbandDataPt->m_predData.m_predVal = poleVal; + + /* Create (2^(-7)) * sgn(invQ) in Q22 format. */ + if (invQ == 0) + { + invQincr_pos = 0L; + } + else + { + invQincr_pos = 0x800000; + } + if (invQ < 0L) + { + invQincr_pos = -invQincr_pos; + } + + invQincr_neg = 0x0080 - invQincr_pos; + invQincr_pos += 0x0080; + + pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 24; + cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer]; + /* partial manual unrolling to improve performance */ + if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 24) + SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0; + + SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ; + + /* Iterate over the number of coefficients for this subband */ + oldZData = invQ; + accL = 0; + for (k = 0; k < 24; k++) + { + int32_t zData0; + int32_t coeffValue; + + zData0 = (*(cbuf_pt--)); + coeffValue = *(zeroCoeffPt + k); + if (zData0 < 0L) + { + acc = invQincr_neg - coeffValue; + } + else + { + acc = invQincr_pos - coeffValue; + } + if (((acc << 23) ^ 0x80000000) == 0) coeffValue--; + acc = (acc >> 8) + coeffValue; + accL += (int64_t)acc * (int64_t)(oldZData); + oldZData = zData0; + *(zeroCoeffPt + k) = acc; + } + + acc = (int32_t)(accL >> 22); + acc = ssat24(acc); + + /* Predictor output is the sum of the pole and zero filter outputs. Ensure + * this is saturated, if necessary. + * recover value of PoleVal stored at beginning of routine... */ + predVal = acc + SubbandDataPt->m_predData.m_predVal; + predVal = ssat24(predVal); + SubbandDataPt->m_predData.m_zeroVal = acc; + SubbandDataPt->m_predData.m_predVal = predVal; + + /* Update the zero filter delay line by writing the new input sample to the + * circular buffer. */ + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 24] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; +} + +XBT_INLINE_ void performPredictionFilteringHL(const int32_t invQ, Subband_data* SubbandDataPt) +{ + int32_t poleVal; + int32_t acc; + int64_t accL; + uint32_t pointer; + int32_t poleDelayLine; + int32_t predVal; + int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff; + int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff; + int32_t* cbuf_pt; + int32_t invQincr_pos; + int32_t invQincr_neg; + int32_t k; + int32_t oldZData; + const int32_t roundCte = 0x80000000; + /* Pole coefficient and data indicies */ + enum { a1 = 0, a2 = 1 }; + + /* Write the newest pole input sample to the pole delay line. + * Ensure the sum of the current dequantised error and the previous + * predictor output is saturated if necessary. */ + poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal; + + poleDelayLine = ssat24(poleDelayLine); + + /* Pole filter convolution. Shift convolution result 1 place to the left + * before retrieving it, since the pole coefficients are Q22 (data is Q23) + * and we want a Q23 result */ + accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]); + /* Update the pole delay line for the next pass by writing the new input + * sample into the 2nd element */ + SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine; + accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine); + poleVal = (int32_t)(accL >> 22); + poleVal = ssat24(poleVal); + + /* Create (2^(-7)) * sgn(invQ) in Q22 format. */ + invQincr_pos = 0L; + if (invQ != 0) + { + invQincr_pos = 0x800000; + } + if (invQ < 0L) + { + invQincr_pos = -invQincr_pos; + } + + invQincr_neg = 0x0080 - invQincr_pos; + invQincr_pos += 0x0080; + + pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 6; + cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer]; + /* partial manual unrolling to improve performance */ + if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 6) + SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0; + + SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ; + + /* Iterate over the number of coefficients for this subband */ + oldZData = invQ; + accL = 0; + + for (k = 0; k < 6; k++) + { + uint32_t tmp_round0; + int32_t coeffValue; + int32_t zData0; + + /* ------------------------------------------------------------------*/ + zData0 = (*(cbuf_pt--)); + coeffValue = *(zeroCoeffPt + k); + if (zData0 < 0L) + { + acc = invQincr_neg - coeffValue; + } + else + { + acc = invQincr_pos - coeffValue; + } + tmp_round0 = acc; + acc = (acc >> 8) + coeffValue; + if (((tmp_round0 << 23) ^ roundCte) == 0) acc--; + accL += (int64_t)acc * (int64_t)(oldZData); + oldZData = zData0; + *(zeroCoeffPt + k) = acc; + } + + acc = (int32_t)(accL >> 22); + acc = ssat24(acc); + + /* Predictor output is the sum of the pole and zero filter outputs. Ensure + * this is saturated, if necessary. */ + predVal = acc + poleVal; + predVal = ssat24(predVal); + SubbandDataPt->m_predData.m_zeroVal = acc; + SubbandDataPt->m_predData.m_predVal = predVal; + + /* Update the zero filter delay line by writing the new input sample to the + * circular buffer. */ + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; + SubbandDataPt->m_predData.m_zeroDelayLine.buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 6] = SubbandDataPt->m_predData.m_zeroDelayLine.modulo; +} + + +#endif //SUBBANDFUNCTIONSCOMMON_H diff --git a/system/embdrv/encoder_for_aptxhd/src/SyncInserter.h b/system/embdrv/encoder_for_aptxhd/src/SyncInserter.h new file mode 100644 index 00000000000..f393a0d223e --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/SyncInserter.h @@ -0,0 +1,114 @@ +/*------------------------------------------------------------------------------ + * + * All declarations relevant for the SyncInserter class. This class exposes a + * public interface that lets a client supply two aptX HD encoder objects (left + * and right stereo channel) and have the current quantised codes adjusted to + * bury an autosync bit. + * + *----------------------------------------------------------------------------*/ +#ifndef SYNCINSERTER_H +#define SYNCINSERTER_H +#ifdef _GCC + #pragma GCC visibility push(hidden) +#endif + + +#include "AptxParameters.h" + + +/* Function to insert sync information into one of the 8 + * quantised codes spread across 2 aptX HD codewords (1 codeword + * per channel) */ +XBT_INLINE_ void xbtEncinsertSync(Encoder_data* leftChannelEncoder, Encoder_data* rightChannelEncoder, uint32_t* syncWordPhase) +{ + /* Currently using 0x1 as the 8-bit sync pattern */ + static const uint32_t syncWord = 0x1; + uint32_t tmp_var; + + uint32_t i; + + /* Variable to hold the XOR of all the quantised code lsbs */ + uint32_t xorCodeLsbs; + + /* Variable to point to the quantiser with the minimum calculated distance + * penalty. */ + Quantiser_data* minPenaltyQuantiser; + + /* Get the vector of quantiser pointers from the left and right encoders */ + Quantiser_data* leftQuant[4]; + Quantiser_data* rightQuant[4]; + leftQuant[0] = &leftChannelEncoder->m_qdata[0]; + leftQuant[1] = &leftChannelEncoder->m_qdata[1]; + leftQuant[2] = &leftChannelEncoder->m_qdata[2]; + leftQuant[3] = &leftChannelEncoder->m_qdata[3]; + rightQuant[0] = &rightChannelEncoder->m_qdata[0]; + rightQuant[1] = &rightChannelEncoder->m_qdata[1]; + rightQuant[2] = &rightChannelEncoder->m_qdata[2]; + rightQuant[3] = &rightChannelEncoder->m_qdata[3]; + + /* Starting quantiser traversal with the LL quantiser from the left channel. + * Initialise the pointer to the minimum penalty quantiser with the details + * of the left LL quantiser. Initialise the code lsbs XOR variable with the + * left LL quantised code lsbs and also XOR in the left and right random + * dither bit generated by the 2 encoders. */ + xorCodeLsbs = + ((rightQuant[LL]->qCode) & 0x1) ^ + leftChannelEncoder->m_dithSyncRandBit ^ + rightChannelEncoder->m_dithSyncRandBit; + minPenaltyQuantiser = rightQuant[LH]; + + /* Traverse across the LH, HL and HH quantisers from the right channel */ + for (i = LH; i <= HH; i++) + { + /* XOR in the lsb of the quantised code currently examined */ + xorCodeLsbs ^= (rightQuant[i]->qCode) & 0x1; + } + + /* If the distance penalty associated with a quantiser is less than the + * current minimum, then make that quantiser the minimum penalty + * quantiser. */ + if (rightQuant[HL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[HL]; + if (rightQuant[LL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[LL]; + if (rightQuant[HH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = rightQuant[HH]; + + /* Traverse across all quantisers from the left channel */ + for (i = LL; i <= HH; i++) + { + /* XOR in the lsb of the quantised code currently examined */ + xorCodeLsbs ^= (leftQuant[i]->qCode) & 0x1; + } + + /* If the distance penalty associated with a quantiser is less than the + * current minimum, then make that quantiser the minimum penalty + * quantiser. */ + if (leftQuant[LH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[LH]; + if (leftQuant[HL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[HL]; + if (leftQuant[LL]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[LL]; + if (leftQuant[HH]->distPenalty < minPenaltyQuantiser->distPenalty) + minPenaltyQuantiser = leftQuant[HH]; + + /* If the lsbs of all 8 quantised codes don't happen to equal the desired + * sync bit to embed, then force them to be by replacing the optimum code + * with the alternate code in the minimum penalty quantiser (changes the lsb + * of the code in this quantiser) */ + if (xorCodeLsbs != ((syncWord >> (*syncWordPhase)) & 0x1)) + { + minPenaltyQuantiser->qCode = minPenaltyQuantiser->altQcode; + } + + /* Decrement the selected sync word bit modulo 8 for the next pass. */ + tmp_var = --(*syncWordPhase); + (*syncWordPhase) = tmp_var & 0x7; +} + + +#ifdef _GCC + #pragma GCC visibility pop +#endif +#endif //SYNCINSERTER_H diff --git a/system/embdrv/encoder_for_aptxhd/src/aptXHDbtenc.c b/system/embdrv/encoder_for_aptxhd/src/aptXHDbtenc.c new file mode 100644 index 00000000000..9eac1a378e3 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/aptXHDbtenc.c @@ -0,0 +1,179 @@ +#include "AptxParameters.h" +#include "AptxTables.h" +#include "aptXHDbtenc.h" +#include "AptxEncoder.h" +#include "SyncInserter.h" +#include "CodewordPacker.h" +#include "swversion.h" + + +typedef struct aptxhdbtenc_t +{ + /* m_endian should either be 0 (little endian) or 8 (big endian). */ + int32_t m_endian; + + /* Autosync inserter & Checker for use with the stereo aptX HD codec. */ + /* The current phase of the sync word insertion (7 down to 0) */ + uint32_t m_syncWordPhase; + + /* Stereo channel aptX HD encoder (annotated to produce Kalimba test vectors + * for it's I/O. This will process valid PCM from a WAV file). */ + /* Each Encoder_data structure requires 1592 bytes */ + Encoder_data m_encoderData[2]; + Qmf_storage m_qmf_l; + Qmf_storage m_qmf_r; +} aptxhdbtenc; + +/* Constants */ +/* Log to linear lookup table used in inverse quantiser*/ +/* Size of Table: 32*4 = 128 bytes */ +static const int32_t IQuant_tableLogT[32] = +{ 16384 * 256, 16744 * 256, 17112 * 256, 17488 * 256, + 17864 * 256, 18256 * 256, 18656 * 256, 19064 * 256, + 19480 * 256, 19912 * 256, 20344 * 256, 20792 * 256, + 21248 * 256, 21712 * 256, 22192 * 256, 22672 * 256, + 23168 * 256, 23680 * 256, 24200 * 256, 24728 * 256, + 25264 * 256, 25824 * 256, 26384 * 256, 26968 * 256, + 27552 * 256, 28160 * 256, 28776 * 256, 29408 * 256, + 30048 * 256, 30704 * 256, 31376 * 256, 32064 * 256 +}; + + +void clearmem_HD(void* mem, int32_t sz) +{ + int8_t* m = (int8_t*)mem; + int32_t i = 0; + for (; i < sz; i++) + { + *m = 0; + m++; + } +} + +APTXHDBTENCEXPORT int SizeofAptxhdbtenc() +{ + return (sizeof(aptxhdbtenc)); +} + +APTXHDBTENCEXPORT const char* aptxhdbtenc_version() +{ + return (swversion); +} + +APTXHDBTENCEXPORT int aptxhdbtenc_init(void* _state, short endian) +{ + aptxhdbtenc* state = (aptxhdbtenc*)_state; + int32_t j = 0; + int32_t k; + int32_t t; + + clearmem_HD(_state, sizeof(aptxhdbtenc)); + + if (state == 0) + return 1; + state->m_syncWordPhase = 7L; + + if (endian == 0) + { + state->m_endian = 0; + } + else + { + state->m_endian = 8; + } + + for (j = 0; j < 2; j++) + { + Encoder_data* encode_dat = &state->m_encoderData[j]; + uint32_t i; + + /* Create a quantiser and subband processor for each suband */ + for (i = LL; i <= HH; i++) + { + encode_dat->m_codewordHistory = 0L; + + encode_dat->m_qdata[i].thresholdTablePtr = subbandParameters[i].threshTable; + encode_dat->m_qdata[i].thresholdTablePtr_sl1 = subbandParameters[i].threshTable_sl1; + encode_dat->m_qdata[i].ditherTablePtr = subbandParameters[i].dithTable; + encode_dat->m_qdata[i].minusLambdaDTable = subbandParameters[i].minusLambdaDTable; + encode_dat->m_qdata[i].codeBits = subbandParameters[i].numBits; + encode_dat->m_qdata[i].qCode = 0L; + encode_dat->m_qdata[i].altQcode = 0L; + encode_dat->m_qdata[i].distPenalty = 0L; + + /* initialisation of inverseQuantiser data */ + encode_dat->m_SubbandData[i].m_iqdata.thresholdTablePtr = subbandParameters[i].threshTable; + encode_dat->m_SubbandData[i].m_iqdata.thresholdTablePtr_sl1 = subbandParameters[i].threshTable_sl1; + encode_dat->m_SubbandData[i].m_iqdata.ditherTablePtr_sf1 = subbandParameters[i].dithTable_sh1; + encode_dat->m_SubbandData[i].m_iqdata.incrTablePtr = subbandParameters[i].incrTable; + encode_dat->m_SubbandData[i].m_iqdata.maxLogDelta = subbandParameters[i].maxLogDelta; + encode_dat->m_SubbandData[i].m_iqdata.minLogDelta = subbandParameters[i].minLogDelta; + encode_dat->m_SubbandData[i].m_iqdata.delta = 0; + encode_dat->m_SubbandData[i].m_iqdata.logDelta = 0; + encode_dat->m_SubbandData[i].m_iqdata.invQ = 0; + encode_dat->m_SubbandData[i].m_iqdata.iquantTableLogPtr = &IQuant_tableLogT[0]; + + // Initializing data for predictor filter + encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.modulo = subbandParameters[i].numZeros; + + for (t = 0; t < 48; t++) + { + encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.buffer[t] = 0; + } + + encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.pointer = 0; + /* Initialise the previous zero filter output and predictor output to zero */ + encode_dat->m_SubbandData[i].m_predData.m_zeroVal = 0L; + encode_dat->m_SubbandData[i].m_predData.m_predVal = 0L; + encode_dat->m_SubbandData[i].m_predData.m_numZeros = subbandParameters[i].numZeros; + /* Initialise the contents of the pole data delay line to zero */ + encode_dat->m_SubbandData[i].m_predData.m_poleDelayLine[0] = 0L; + encode_dat->m_SubbandData[i].m_predData.m_poleDelayLine[1] = 0L; + + for (k = 0; k < 24; k++) + { + encode_dat->m_SubbandData[i].m_ZeroCoeffData.m_zeroCoeff[k] = 0; + } + + // Initializing data for zerocoeff update function. + encode_dat->m_SubbandData[i].m_ZeroCoeffData.m_numZeros = subbandParameters[i].numZeros; + + /* Initializing data for PoleCoeff update function. + * Fill the adaptation delay line with +1 initially */ + encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleAdaptDelayLine.s32 = 0x00010001; + + /* Zero the pole coefficients */ + encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleCoeff[0] = 0L; + encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleCoeff[1] = 0L; + } + } + return 0; +} + +APTXHDBTENCEXPORT int aptxhdbtenc_encodestereo(void* _state, void* _pcmL, void* _pcmR, void* _buffer) +{ + aptxhdbtenc* state = (aptxhdbtenc*)_state; + int32_t* pcmL = (int32_t*)_pcmL; + int32_t* pcmR = (int32_t*)_pcmR; + int32_t* buffer = (int32_t*)_buffer; + int32_t tmp_reg; + + //Feed the PCM to the dual aptX HD encoders + aptxhdEncode(pcmL, &state->m_qmf_l, &state->m_encoderData[0]); + aptxhdEncode(pcmR, &state->m_qmf_r, &state->m_encoderData[1]); + + //Insert the autosync information into the stereo quantised codes + xbtEncinsertSync(&state->m_encoderData[0], &state->m_encoderData[1], &state->m_syncWordPhase); + + aptxhdPostEncode(&state->m_encoderData[0]); + aptxhdPostEncode(&state->m_encoderData[1]); + + //Pack the (possibly adjusted) codes into a 24-bit codeword per channel + tmp_reg = packCodeword(&state->m_encoderData[0]); + buffer[0] = (int32_t)tmp_reg; + + tmp_reg = packCodeword(&state->m_encoderData[1]); + buffer[1] = (int32_t)tmp_reg; + + return 0; +} diff --git a/system/embdrv/encoder_for_aptxhd/src/swversion.h b/system/embdrv/encoder_for_aptxhd/src/swversion.h new file mode 100644 index 00000000000..7ca62d48845 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/src/swversion.h @@ -0,0 +1,8 @@ +#ifndef SWVERSION_H +#define SWVERSION_H + + +const char* swversion = "1.0.0"; + + +#endif //SWVERSION_H -- GitLab