diff --git a/TEST_MAPPING b/TEST_MAPPING old mode 100755 new mode 100644 index 69a0709acb61c1dcbddbfd49052dbfbc469a1d49..65f2fefd19eeb4efa4c28a7848210d4673a427c9 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -62,6 +62,12 @@ { "name" : "net_test_btif_hf_client_service" }, + { + "name" : "libaptx_enc_tests" + }, + { + "name" : "libaptxhd_enc_tests" + }, { "name" : "net_test_stack_btm" } diff --git a/apex/apex_manifest.json b/apex/apex_manifest.json index e396cbc9a5790f3737a918858688139b2367c5ca..ceb007294c0bddca802d30c92f631c0e6ebf40d7 100644 --- a/apex/apex_manifest.json +++ b/apex/apex_manifest.json @@ -10,7 +10,5 @@ ], "name": "com.android.btservices", "requireNativeLibs": [ - "libaptX_encoder.so", - "libaptXHD_encoder.so" ] } diff --git a/system/embdrv/encoder_for_aptx/Android.bp b/system/embdrv/encoder_for_aptx/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..502759e92500dbb40dac968696d9f0957e26a796 --- /dev/null +++ b/system/embdrv/encoder_for_aptx/Android.bp @@ -0,0 +1,35 @@ +tidy_errors = [ + "*", + "-altera-struct-pack-align", + "-altera-unroll-loops", + "-bugprone-narrowing-conversions", + "-cppcoreguidelines-avoid-magic-numbers", + "-cppcoreguidelines-init-variables", + "-cppcoreguidelines-narrowing-conversions", + "-hicpp-signed-bitwise", + "-readability-identifier-length", + "-readability-magic-numbers", +] + +cc_library_static { + name: "libaptx_enc", + host_supported: true, + export_include_dirs: ["include"], + srcs: [ + "src/aptXbtenc.c", + "src/ProcessSubband.c", + "src/QmfConv.c", + "src/QuantiseDifference.c", + ], + cflags: ["-O2", "-Werror", "-Wall", "-Wextra"], + tidy: true, + tidy_checks: tidy_errors, + tidy_checks_as_errors: tidy_errors, + min_sdk_version: "Tiramisu", + apex_available: [ + "com.android.btservices", + ], + visibility: [ + "//packages/modules/Bluetooth:__subpackages__", + ], +} diff --git a/system/embdrv/encoder_for_aptx/include/aptXbtenc.h b/system/embdrv/encoder_for_aptx/include/aptXbtenc.h index 47aa29309c6a1e894fb8128fd91b5409d61a437a..bce6ee7527b4675e27a2ae1fa9d6c621b35c74e7 100644 --- a/system/embdrv/encoder_for_aptx/include/aptXbtenc.h +++ b/system/embdrv/encoder_for_aptx/include/aptXbtenc.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * This file exposes a public interface to allow clients to invoke aptX @@ -9,6 +24,8 @@ #ifndef APTXBTENC_H #define APTXBTENC_H +#include <stdint.h> + #ifdef __cplusplus extern "C" { #endif @@ -35,18 +52,20 @@ APTXBTENCEXPORT const char* aptxbtenc_version(void); * 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. */ +/* 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); +APTXBTENCEXPORT int aptxbtenc_encodestereo(void* _state, void* _pcmL, + void* _pcmR, void* _buffer); #ifdef __cplusplus -} // /extern "C" +} // /extern "C" #endif -#endif //APTXBTENC_H +#endif // APTXBTENC_H diff --git a/system/embdrv/encoder_for_aptx/src/AptxEncoder.h b/system/embdrv/encoder_for_aptx/src/AptxEncoder.h index 81b75d04a5eca0b8eec385ebfd04924cbc46f609..5f7ceecf12fc75c4afe3f0af048867f03627f927 100644 --- a/system/embdrv/encoder_for_aptx/src/AptxEncoder.h +++ b/system/embdrv/encoder_for_aptx/src/AptxEncoder.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * All declarations relevant for aptxEncode. This function allows clients @@ -10,71 +25,77 @@ #ifndef APTXENCODER_H #define APTXENCODER_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#pragma GCC visibility push(hidden) #endif #include "AptxParameters.h" #include "DitherGenerator.h" +#include "Qmf.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]; +/* 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; - } + /* 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); + /* 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 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]); + /* 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); +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); + 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); + 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); + 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 +#pragma GCC visibility pop #endif -#endif //APTXENCODER_H +#endif // APTXENCODER_H diff --git a/system/embdrv/encoder_for_aptx/src/AptxParameters.h b/system/embdrv/encoder_for_aptx/src/AptxParameters.h index f8a7d04532a3136f01ad9cda178a3d64ed95a308..4735fd82e65b2853ac085f805b96937f756ab6e8 100644 --- a/system/embdrv/encoder_for_aptx/src/AptxParameters.h +++ b/system/embdrv/encoder_for_aptx/src/AptxParameters.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * General shared aptX parameters. @@ -7,108 +22,99 @@ #ifndef APTXPARAMETERS_H #define APTXPARAMETERS_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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 +#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 +#define XBT_INLINE_ inline +#define _STDQMFOUTERCOEFF 1 #else - #define XBT_INLINE_ static - #define _STDQMFOUTERCOEFF 1 +#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; +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 - { +typedef union u_reg64 { + uint64_t u64; + int64_t s64; + struct s_u32 { #ifdef __BIGENDIAN - uint32_t h; - uint32_t l; + uint32_t h; + uint32_t l; #else - uint32_t l; - uint32_t h; + uint32_t l; + uint32_t h; #endif - } u32; + } u32; - struct s_s32 - { + struct s_s32 { #ifdef __BIGENDIAN - int32_t h; - int32_t l; + int32_t h; + int32_t l; #else - int32_t l; - int32_t h; + int32_t l; + int32_t h; #endif - } s32; + } s32; } reg64_t; -typedef union u_reg32 -{ - uint32_t u32; - int32_t s32; +typedef union u_reg32 { + uint32_t u32; + int32_t s32; - struct s_u16 - { + struct s_u16 { #ifdef __BIGENDIAN - uint16_t h; - uint16_t l; + uint16_t h; + uint16_t l; #else - uint16_t l; - uint16_t h; + uint16_t l; + uint16_t h; #endif - } u16; - struct s_s16 - { + } u16; + struct s_s16 { #ifdef __BIGENDIAN - int16_t h; - int16_t l; + int16_t h; + int16_t l; #else - int16_t l; - int16_t h; + int16_t l; + int16_t h; #endif - } s16; + } 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 PCM data indices. */ +enum { FirstPcm = 0, SecondPcm = 1, ThirdPcm = 2, FourthPcm = 3 }; /* Symbolic constants for sync modes. */ -enum {stereo=0, dualmono=1, no_sync=2}; +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; +typedef enum { LL = 0, LH = 1, HL = 2, HH = 3 } bands; /* Structure declaration to bind a set of subband parameters */ -typedef struct -{ +typedef struct { const int32_t* threshTable; const int32_t* threshTable_sl1; const int32_t* dithTable; @@ -121,117 +127,116 @@ typedef struct int32_t numZeros; } SubbandParameters; -/* Struct required for the polecoeffcalculator function of bt-aptX encoder and decoder*/ +/* 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]; +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*/ +/* 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]; +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*/ +/* 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; +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*/ +/* 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; +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*/ +/* 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; +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; +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]; +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 */ +/* 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. */ @@ -240,8 +245,7 @@ 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 +#pragma GCC visibility pop #endif -#endif //APTXPARAMETERS_H +#endif // APTXPARAMETERS_H diff --git a/system/embdrv/encoder_for_aptx/src/AptxTables.h b/system/embdrv/encoder_for_aptx/src/AptxTables.h index e357b50e664d4647d2430edeb115f3ca3eedbb17..7c017bfcdf498d72991eea29bd8cca9ed18b2b6c 100644 --- a/system/embdrv/encoder_for_aptx/src/AptxTables.h +++ b/system/embdrv/encoder_for_aptx/src/AptxTables.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * All table definitions used for the quantizer. @@ -7,418 +22,131 @@ #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, +/* 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 q2incr16[3] = { + 0, + -33, + 136, }; -static const int32_t dq2dith16_sf1[3] = -{ - 194080, - 194080, - 502402, +static const int32_t dq2dith16_sf1[3] = { + 194080, + 194080, + 502402, }; -static const int32_t dq2mLamb16[2] = -{ - 0, - -77081, +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, +/* 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 q3incr16[5] = { + 0, -8, 33, 95, 262, }; -static const int32_t dq3dith16_sf1[5] = -{ - 163006, - 163006, - 216698, - 361148, - 1187538, +static const int32_t dq3dith16_sf1[5] = { + 163006, 163006, 216698, 361148, 1187538, }; -static const int32_t dq3mLamb16[4] = -{ - 0, - -13423, - -36113, - -206598, +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, +/* 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 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 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, +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, +/* 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 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 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, +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 }, +static const SubbandParameters subbandParameters[NUMSUBBANDS] = { + /* LL band */ + {0, dq7bit16_sl1, 0, dq7dith16_sf1, dq7mLamb16, q7incr16, 7, (18 * 256) - 1, + -20, 24}, - /* HL band */ - { 0, dq2bit16_sl1, 0, dq2dith16_sf1, dq2mLamb16, q2incr16, 2, (23*256)-1, -25, 6 }, + /* LH band */ + {0, dq4bit16_sl1, 0, dq4dith16_sf1, dq4mLamb16, q4incr16, 4, (21 * 256) - 1, + -23, 12}, - /* HH band */ - { 0, dq3bit16_sl1, 0, dq3dith16_sf1, dq3mLamb16, q3incr16, 3, (22*256)-1, -24, 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 +#endif // APTXTABLES_H diff --git a/system/embdrv/encoder_for_aptx/src/CBStruct.h b/system/embdrv/encoder_for_aptx/src/CBStruct.h index b3d77cfebb592ad344b18f2da63e68e80df54f3a..eb968d66501b8b943ad66131bd4d0713da74e6a0 100644 --- a/system/embdrv/encoder_for_aptx/src/CBStruct.h +++ b/system/embdrv/encoder_for_aptx/src/CBStruct.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Structure required to implement a circular buffer. @@ -7,22 +22,19 @@ #ifndef CBSTRUCT_H #define CBSTRUCT_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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; - +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 +#pragma GCC visibility pop #endif -#endif //CBSTRUCT_H \ No newline at end of file +#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 index 688245b321377bb1d8a76fdfc7171bf8cac69ea1..a4b96ebf95c6a206b7b0714d1c4e923ddf30ebe1 100644 --- a/system/embdrv/encoder_for_aptx/src/CodewordPacker.h +++ b/system/embdrv/encoder_for_aptx/src/CodewordPacker.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Prototype declaration of the CodewordPacker Function @@ -10,50 +25,40 @@ #ifndef CODEWORDPACKER_H #define CODEWORDPACKER_H - #include "AptxParameters.h" +XBT_INLINE_ int16_t packCodeword(Encoder_data* EncoderDataPt, + uint32_t aligned) { + int32_t syncContribution; + int32_t hhCode; + int32_t codeword; -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; - /* 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; + /* 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 (int16_t)codeword; } - -#endif //CODEWORDPACKER_H +#endif // CODEWORDPACKER_H diff --git a/system/embdrv/encoder_for_aptx/src/DitherGenerator.h b/system/embdrv/encoder_for_aptx/src/DitherGenerator.h index 9b4c686f8a5892f05cd44aa532608e305526b844..3c4f24ccf55c1699641f38aa671d568e62d15e4f 100644 --- a/system/embdrv/encoder_for_aptx/src/DitherGenerator.h +++ b/system/embdrv/encoder_for_aptx/src/DitherGenerator.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * These functions allow clients to update an internal codeword history @@ -9,94 +24,91 @@ #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 = +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; + 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; +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 +#endif // DITHERGENERATOR_H diff --git a/system/embdrv/encoder_for_aptx/src/ProcessSubband.c b/system/embdrv/encoder_for_aptx/src/ProcessSubband.c index 0dfbb4fa8cb3e2dfa905fc45da52a36240e8124b..e1cc1e35f4928b36e0b14eaca3cc3e6a7f676852 100644 --- a/system/embdrv/encoder_for_aptx/src/ProcessSubband.c +++ b/system/embdrv/encoder_for_aptx/src/ProcessSubband.c @@ -1,43 +1,64 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "AptxParameters.h" -#include "SubbandFunctionsCommon.h" #include "SubbandFunctions.h" +#include "SubbandFunctionsCommon.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); -/* 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 pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, + SubbandDataPt->m_predData.m_zeroVal, + &SubbandDataPt->m_PoleCoeffData); - /* Predictor filtering */ - performPredictionFiltering(iqDataPt->invQ, SubbandDataPt); + /* 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); +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 pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, + SubbandDataPt->m_predData.m_zeroVal, + &SubbandDataPt->m_PoleCoeffData); - /* Predictor filtering */ - performPredictionFilteringLL(iqDataPt->invQ, SubbandDataPt); + /* 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); +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 pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, + SubbandDataPt->m_predData.m_zeroVal, + &SubbandDataPt->m_PoleCoeffData); - /* Predictor filtering */ - performPredictionFilteringHL(iqDataPt->invQ, SubbandDataPt); + /* 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 index acc6696b7478bf5f997e78a1c9bf5dae84fc131b..2e56ee9081fa3c5ca503b9dfff625b2921e6c011 100644 --- a/system/embdrv/encoder_for_aptx/src/Qmf.h +++ b/system/embdrv/encoder_for_aptx/src/Qmf.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * This file includes the coefficient tables or the two convolution function @@ -9,134 +24,138 @@ #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; +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 +static 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 +static 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 +static 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; +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 +#endif // QMF_H diff --git a/system/embdrv/encoder_for_aptx/src/QmfConv.c b/system/embdrv/encoder_for_aptx/src/QmfConv.c index 14e342ef5ae692ba19ba9d21fdec970dee6feccf..4f24d1e894f73f9eacd522c9446c1a01b9a14c3d 100644 --- a/system/embdrv/encoder_for_aptx/src/QmfConv.c +++ b/system/embdrv/encoder_for_aptx/src/QmfConv.c @@ -1,327 +1,360 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * 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; +#include "Qmf.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] = 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] = 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; +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] = 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] = 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 index 17e412d230fffa77a366c76b4d84a45010d34286..5f6c865859bc51e5438717ac057e5713c609ce96 100644 --- a/system/embdrv/encoder_for_aptx/src/QuantiseDifference.c +++ b/system/embdrv/encoder_for_aptx/src/QuantiseDifference.c @@ -1,711 +1,771 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "AptxParameters.h" -#include "Quantiser.h" #include "AptxTables.h" +#include "Quantiser.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 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 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; + return (tmp_acc.s64 <= 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 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); +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 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) - dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = 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 = (int32_t)((uint32_t)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 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) - dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = 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 = (int32_t)((uint32_t)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 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) - dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = 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 = (int32_t)((uint32_t)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; +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) - dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = 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 = (int32_t)((uint32_t)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 index 63a32c659051ee3d8b2689211d5e4991b30ad9e1..16f0416c07646d75ecd5716514f04ecc9a0d24df 100644 --- a/system/embdrv/encoder_for_aptx/src/Quantiser.h +++ b/system/embdrv/encoder_for_aptx/src/Quantiser.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Function to calculate a quantised representation of an input @@ -8,20 +23,21 @@ #ifndef QUANTISER_H #define QUANTISER_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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); - +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 +#pragma GCC visibility pop #endif -#endif //QUANTISER_H +#endif // QUANTISER_H diff --git a/system/embdrv/encoder_for_aptx/src/SubbandFunctions.h b/system/embdrv/encoder_for_aptx/src/SubbandFunctions.h index b8e743d480caf4c1d9571f89ab55bd3b8167651e..16c1b9fb2d2471020b654d19faf000c0f2454452 100644 --- a/system/embdrv/encoder_for_aptx/src/SubbandFunctions.h +++ b/system/embdrv/encoder_for_aptx/src/SubbandFunctions.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Subband processing consists of: @@ -10,175 +25,162 @@ #ifndef SUBBANDFUNCTIONS_H #define SUBBANDFUNCTIONS_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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]; +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 indices 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 indices 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; + } else 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; + } else { // 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 = (int32_t)((uint32_t)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 +#pragma GCC visibility pop #endif -#endif //SUBBANDFUNCTIONS_H +#endif // SUBBANDFUNCTIONS_H diff --git a/system/embdrv/encoder_for_aptx/src/SubbandFunctionsCommon.h b/system/embdrv/encoder_for_aptx/src/SubbandFunctionsCommon.h index 3f8f05e240d4dc9219804f9a5fb83525823b6100..61fbc16712d4e76613b4e3ec4ff3cadc8ca9df45 100644 --- a/system/embdrv/encoder_for_aptx/src/SubbandFunctionsCommon.h +++ b/system/embdrv/encoder_for_aptx/src/SubbandFunctionsCommon.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Subband processing consists of: @@ -10,506 +25,487 @@ #ifndef SUBBANDFUNCTIONSCOMMON_H #define SUBBANDFUNCTIONSCOMMON_H +enum reg64_reg { reg64_H = 1, reg64_L = 0 }; -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); - +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; +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; +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 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 indices */ + 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 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 indices */ + 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; +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 indices */ + 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 +#endif // SUBBANDFUNCTIONSCOMMON_H diff --git a/system/embdrv/encoder_for_aptx/src/SyncInserter.h b/system/embdrv/encoder_for_aptx/src/SyncInserter.h index 347fd50b49e9113acd11a90fca181e33356225de..f36a5f0c036e643b8d85700195709e77f30a59f7 100644 --- a/system/embdrv/encoder_for_aptx/src/SyncInserter.h +++ b/system/embdrv/encoder_for_aptx/src/SyncInserter.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * All declarations relevant for the SyncInserter class. This class exposes a @@ -10,208 +25,198 @@ #ifndef SYNCINSERTER_H #define SYNCINSERTER_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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 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; +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 +#pragma GCC visibility pop #endif -#endif //SYNCINSERTER_H +#endif // SYNCINSERTER_H diff --git a/system/embdrv/encoder_for_aptx/src/aptXbtenc.c b/system/embdrv/encoder_for_aptx/src/aptXbtenc.c index 4fde99262fbcbcd59c6ea88b7391958d3b2feb56..6286ca942d96c5707de9f9aead556e90c04f2ee9 100644 --- a/system/embdrv/encoder_for_aptx/src/aptXbtenc.c +++ b/system/embdrv/encoder_for_aptx/src/aptXbtenc.c @@ -1,218 +1,227 @@ -#include "AptxParameters.h" -#include "AptxTables.h" +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "aptXbtenc.h" + #include "AptxEncoder.h" -#include "SyncInserter.h" +#include "AptxParameters.h" +#include "AptxTables.h" #include "CodewordPacker.h" +#include "SyncInserter.h" #include "swversion.h" +typedef struct aptxbtenc_t { + /* m_endian should either be 0 (little endian) or 8 (big endian). */ + int32_t m_endian; -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; + /* 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; + /* 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 + /* 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; + /* 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)); +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}; + +static 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 const char* aptxbtenc_version() -{ - return (swversion); -} +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-compatibility 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; + } -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; + 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; } - } - return 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; +APTXBTENCEXPORT int aptxbtenc_setsync_mode(void* _state, int32_t sync_mode) { + aptxbtenc* state = (aptxbtenc*)_state; + state->m_sync_mode = sync_mode; - return 0; + 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; +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; + int16_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] = 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] = tmp_out; + + return 0; } diff --git a/system/embdrv/encoder_for_aptx/src/swversion.h b/system/embdrv/encoder_for_aptx/src/swversion.h index 792b576a8f56fafa0464c77f197652ac098d705d..a55b211377d60599f390344f499c8362a80a7a6a 100644 --- a/system/embdrv/encoder_for_aptx/src/swversion.h +++ b/system/embdrv/encoder_for_aptx/src/swversion.h @@ -1,8 +1,21 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef SWVERSION_H #define SWVERSION_H +static const char* swversion = "1.0.0"; -const char *swversion = "1.0.0"; - - -#endif //SWVERSION_H +#endif // SWVERSION_H diff --git a/system/embdrv/encoder_for_aptxhd/Android.bp b/system/embdrv/encoder_for_aptxhd/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..801563e4ef6bbe1f484887f0d2578c7bf7b89b04 --- /dev/null +++ b/system/embdrv/encoder_for_aptxhd/Android.bp @@ -0,0 +1,35 @@ +tidy_errors = [ + "*", + "-altera-struct-pack-align", + "-altera-unroll-loops", + "-bugprone-narrowing-conversions", + "-cppcoreguidelines-avoid-magic-numbers", + "-cppcoreguidelines-init-variables", + "-cppcoreguidelines-narrowing-conversions", + "-hicpp-signed-bitwise", + "-readability-identifier-length", + "-readability-magic-numbers", +] + +cc_library_static { + name: "libaptxhd_enc", + host_supported: true, + export_include_dirs: ["include"], + srcs: [ + "src/aptXHDbtenc.c", + "src/ProcessSubband.c", + "src/QmfConv.c", + "src/QuantiseDifference.c", + ], + cflags: ["-O2", "-Werror", "-Wall", "-Wextra"], + tidy: true, + tidy_checks: tidy_errors, + tidy_checks_as_errors: tidy_errors, + min_sdk_version: "Tiramisu", + apex_available: [ + "com.android.btservices", + ], + visibility: [ + "//packages/modules/Bluetooth:__subpackages__", + ], +} diff --git a/system/embdrv/encoder_for_aptxhd/include/aptXHDbtenc.h b/system/embdrv/encoder_for_aptxhd/include/aptXHDbtenc.h index bd2bc801c3ed6ea82bf0d8afbd285ac9e51c3bc0..9c18ab1388db689724ede8fac6ad1a567279c393 100644 --- a/system/embdrv/encoder_for_aptxhd/include/aptXHDbtenc.h +++ b/system/embdrv/encoder_for_aptxhd/include/aptXHDbtenc.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*----------------------------------------------------------------------------- * * This file exposes a public interface to allow clients to invoke aptX HD @@ -19,10 +34,9 @@ extern "C" { #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); +APTXHDBTENCEXPORT int SizeofAptxhdbtenc(void); /* aptxhdbtenc_version can be used to extract the version number * of the aptX HD encoder */ @@ -37,13 +51,13 @@ APTXHDBTENCEXPORT const char* aptxhdbtenc_version(void); 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. + * and generate two 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); - +APTXHDBTENCEXPORT int aptxhdbtenc_encodestereo(void* _state, void* _pcmL, + void* _pcmR, void* _buffer); #ifdef __cplusplus -} // /extern "C" +} // /extern "C" #endif -#endif //APTXHDBTENC_H +#endif // APTXHDBTENC_H diff --git a/system/embdrv/encoder_for_aptxhd/src/AptxEncoder.h b/system/embdrv/encoder_for_aptxhd/src/AptxEncoder.h index bfd5fb4f86a1e7c14932d1fb51f5ebb03a39f3a8..600ff345cb51b621c98acd269ad9557f85709e22 100644 --- a/system/embdrv/encoder_for_aptxhd/src/AptxEncoder.h +++ b/system/embdrv/encoder_for_aptxhd/src/AptxEncoder.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * All declarations relevant for aptxhdEncode. This function allows clients @@ -10,78 +25,84 @@ #ifndef APTXENCODER_H #define APTXENCODER_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#pragma GCC visibility push(hidden) #endif - #include "AptxParameters.h" #include "DitherGenerator.h" +#include "Qmf.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 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); +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 +#pragma GCC visibility pop #endif -#endif //APTXENCODER_H +#endif // APTXENCODER_H diff --git a/system/embdrv/encoder_for_aptxhd/src/AptxParameters.h b/system/embdrv/encoder_for_aptxhd/src/AptxParameters.h index b3e9dd3225df9393f345b9c290e8ff7cfd6b944f..cfa9fcbd45e5e486cf8155a2b689a00b79d44faa 100644 --- a/system/embdrv/encoder_for_aptxhd/src/AptxParameters.h +++ b/system/embdrv/encoder_for_aptxhd/src/AptxParameters.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * General shared aptX HD parameters. @@ -7,232 +22,214 @@ #ifndef APTXPARAMETERS_H #define APTXPARAMETERS_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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 +#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 +#define XBT_INLINE_ inline +#define _STDQMFOUTERCOEFF 1 #else - #define XBT_INLINE_ static - #define _STDQMFOUTERCOEFF 1 +#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; +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 - { +typedef union u_reg64 { + uint64_t u64; + int64_t s64; + struct s_u32 { #ifdef __BIGENDIAN - uint32_t h; - uint32_t l; + uint32_t h; + uint32_t l; #else - uint32_t l; - uint32_t h; + uint32_t l; + uint32_t h; #endif - } u32; - struct s_s32 - { + } u32; + struct s_s32 { #ifdef __BIGENDIAN - int32_t h; - int32_t l; + int32_t h; + int32_t l; #else - int32_t l; - int32_t h; + int32_t l; + int32_t h; #endif - } s32; + } s32; } reg64_t; -typedef union u_reg32 -{ - uint32_t u32; - int32_t s32; - struct s_u16 - { +typedef union u_reg32 { + uint32_t u32; + int32_t s32; + struct s_u16 { #ifdef __BIGENDIAN - uint16_t h; - uint16_t l; + uint16_t h; + uint16_t l; #else - uint16_t l; - uint16_t h; + uint16_t l; + uint16_t h; #endif - } u16; - struct s_s16 - { + } u16; + struct s_s16 { #ifdef __BIGENDIAN - int16_t h; - int16_t l; + int16_t h; + int16_t l; #else - int16_t l; - int16_t h; + int16_t l; + int16_t h; #endif - } s16; + } 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 -}; +/* Symbolic constants for PCM data indices. */ +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; +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; +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*/ +/* 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]; +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*/ +/* 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]; +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*/ +/* 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; +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*/ +/* 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; +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*/ +/* 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; +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; +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]; +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. */ @@ -241,8 +238,7 @@ 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 +#pragma GCC visibility pop #endif -#endif //APTXPARAMETERS_H +#endif // APTXPARAMETERS_H diff --git a/system/embdrv/encoder_for_aptxhd/src/AptxTables.h b/system/embdrv/encoder_for_aptxhd/src/AptxTables.h index 5db25e9b36d090f09b14d15bfda7f0601682eafb..460e7abd04e065e44004cfe7feb08d768edd38e5 100644 --- a/system/embdrv/encoder_for_aptxhd/src/AptxTables.h +++ b/system/embdrv/encoder_for_aptxhd/src/AptxTables.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * All table definitions used for the quantizer. @@ -9,1357 +24,210 @@ #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 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, }; -/* 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, +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 - }, +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 - }, + /* 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 - } -}; + /* 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 +#endif // APTXTABLES_H diff --git a/system/embdrv/encoder_for_aptxhd/src/CBStruct.h b/system/embdrv/encoder_for_aptxhd/src/CBStruct.h index 95e4d59e48809702457a3a3652b7843ab40c7e82..97b25f9650501c6f22e34b5a1dc55b583d0f81b6 100644 --- a/system/embdrv/encoder_for_aptxhd/src/CBStruct.h +++ b/system/embdrv/encoder_for_aptxhd/src/CBStruct.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Structure required to implement a circular buffer. @@ -7,22 +22,19 @@ #ifndef CBSTRUCT_H #define CBSTRUCT_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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; +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 +#pragma GCC visibility pop #endif -#endif //CBSTRUCT_H +#endif // CBSTRUCT_H diff --git a/system/embdrv/encoder_for_aptxhd/src/CodewordPacker.h b/system/embdrv/encoder_for_aptxhd/src/CodewordPacker.h index 67a9efbbbfb17fa87caec275dd24104df8d1dc73..90f8c4c358a10c8952cc60ab5ee957b80e26ed36 100644 --- a/system/embdrv/encoder_for_aptxhd/src/CodewordPacker.h +++ b/system/embdrv/encoder_for_aptxhd/src/CodewordPacker.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Prototype declaration of the CodewordPacker Function @@ -10,41 +25,34 @@ #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; +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 +#endif // CODEWORDPACKER_H diff --git a/system/embdrv/encoder_for_aptxhd/src/DitherGenerator.h b/system/embdrv/encoder_for_aptxhd/src/DitherGenerator.h index 60fb15d7f8073fa67517f1c8b2afe651a8b4a669..9202a3e222f08c54a24c6c11d567faf04ca8f2ac 100644 --- a/system/embdrv/encoder_for_aptxhd/src/DitherGenerator.h +++ b/system/embdrv/encoder_for_aptxhd/src/DitherGenerator.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * These functions allow clients to update an internal codeword history @@ -9,93 +24,91 @@ #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 = +/* 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; + 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; +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 +#endif // DITHERGENERATOR_H diff --git a/system/embdrv/encoder_for_aptxhd/src/ProcessSubband.c b/system/embdrv/encoder_for_aptxhd/src/ProcessSubband.c index e4de607c382f987a30ae25f1def98da4bca0d11d..12c45717d7a5c152f2b0b9f1ff886ca4653bec8e 100644 --- a/system/embdrv/encoder_for_aptxhd/src/ProcessSubband.c +++ b/system/embdrv/encoder_for_aptxhd/src/ProcessSubband.c @@ -1,43 +1,66 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "AptxParameters.h" -#include "SubbandFunctionsCommon.h" #include "SubbandFunctions.h" +#include "SubbandFunctionsCommon.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); -/* 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 pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, + SubbandDataPt->m_predData.m_zeroVal, + &SubbandDataPt->m_PoleCoeffData); - /* Predictor filtering */ - performPredictionFiltering(iqDataPt->invQ, SubbandDataPt); + /* 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); +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 pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, + SubbandDataPt->m_predData.m_zeroVal, + &SubbandDataPt->m_PoleCoeffData); - /* Predictor filtering */ - performPredictionFilteringLL(iqDataPt->invQ, SubbandDataPt); + /* 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); +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 pole coefficient update */ + updatePredictorPoleCoefficients(iqDataPt->invQ, + SubbandDataPt->m_predData.m_zeroVal, + &SubbandDataPt->m_PoleCoeffData); - /* Predictor filtering */ - performPredictionFilteringHL(iqDataPt->invQ, SubbandDataPt); + /* 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 index 91d91b8d94fb80ae60eeb33c58f10a157eeee18f..0efb762e7ddd40052705ba8991df716292ae4dc2 100644 --- a/system/embdrv/encoder_for_aptxhd/src/Qmf.h +++ b/system/embdrv/encoder_for_aptxhd/src/Qmf.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * This file includes the coefficient tables or the two convolution function @@ -9,142 +24,146 @@ #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; +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 */ + * 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 +static 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 +static 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 +static 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; +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 +#endif // QMF_H diff --git a/system/embdrv/encoder_for_aptxhd/src/QmfConv.c b/system/embdrv/encoder_for_aptxhd/src/QmfConv.c index 16ab0c8d76c75ced60a73b6ed0bb523636da6a54..5312f65e50f7272b7dc8d65629ac71e062678836 100644 --- a/system/embdrv/encoder_for_aptxhd/src/QmfConv.c +++ b/system/embdrv/encoder_for_aptxhd/src/QmfConv.c @@ -1,337 +1,367 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * 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; +#include "Qmf.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] = 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] = 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; +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] = 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] = 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 index 8b069a52ff3f78e706942aa4791d9dc74a613d70..cac8bf3aeb24059f43eafc76ac7d2ef4b4fd5d74 100644 --- a/system/embdrv/encoder_for_aptxhd/src/QuantiseDifference.c +++ b/system/embdrv/encoder_for_aptxhd/src/QuantiseDifference.c @@ -1,763 +1,834 @@ -#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); +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Quantiser.h" + +XBT_INLINE_ int32_t BsearchLL(const int32_t absDiffSignalShifted, + const int32_t delta, + const int32_t* dqbitTablePrt) { + int32_t qCode = 0; + reg64_t tmp_acc; + int32_t tmp = 0; + int32_t lc_delta = delta << 8; + + 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 BsearchHL(const int32_t absDiffSignalShifted, + const int32_t delta, + const int32_t* dqbitTablePrt) { + int32_t qCode = 0; + reg64_t tmp_acc; + int32_t tmp = 0; + int32_t lc_delta = delta << 8; + + 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); +XBT_INLINE_ int32_t BsearchHH(const int32_t absDiffSignalShifted, + const int32_t delta, + const int32_t* dqbitTablePrt) { + int32_t qCode = 0; + reg64_t tmp_acc; + int32_t tmp = 0; + int32_t lc_delta = delta << 8; + + 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_HDHL(const int32_t diffSignal, const int32_t ditherVal, + const int32_t delta, Quantiser_data* qdata_pt) { + int32_t absDiffSignal = 0; + int32_t absDiffSignalShifted = 0; + int32_t index = 0; + int32_t dithSquared = 0; + int32_t minusLambdaD = 0; + int32_t acc = 0; + int32_t threshDiff = 0; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL = 0; + int32_t tmp_qCode = 0; + int32_t tmp_altQcode = 0; + uint32_t tmp_round0 = 0; + int32_t _delta = 0; + + /* 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) - dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = 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 = (int32_t)((uint32_t)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_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) - dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = 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 = (int32_t)((uint32_t)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; +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 = + 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) - dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = 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 = (int32_t)((uint32_t)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); +static 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; +void quantiseDifference_HDLH(const int32_t diffSignal, const int32_t ditherVal, + const int32_t delta, Quantiser_data* qdata_pt) { + int32_t absDiffSignal = 0; + int32_t absDiffSignalShifted = 0; + int32_t index = 0; + int32_t dithSquared = 0; + int32_t minusLambdaD = 0; + int32_t acc = 0; + int32_t threshDiff = 0; + reg64_t tmp_acc; + reg64_t tmp_reg64; + int32_t tmp_accL = 0; + int32_t tmp_qCode = 0; + int32_t tmp_altQcode = 0; + + uint32_t tmp_round0 = 0; + int32_t _delta = 0; + + /* 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) - dithSquared; + tmp_acc.s64 = (int64_t)tmp_accL * minusLambdaD; + + tmp_round0 = tmp_acc.s32.l << 8; + + acc = (int32_t)(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 = (int32_t)((uint32_t)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 index e08fec476834428886e8e9cf012e9979c560e57d..119f193ed2d24dc4d1fd55ff76bc92d1debfef4a 100644 --- a/system/embdrv/encoder_for_aptxhd/src/Quantiser.h +++ b/system/embdrv/encoder_for_aptxhd/src/Quantiser.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Function to calculate a quantised representation of an input @@ -8,20 +23,21 @@ #ifndef QUANTISER_H #define QUANTISER_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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); - +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 +#pragma GCC visibility pop #endif -#endif //QUANTISER_H +#endif // QUANTISER_H diff --git a/system/embdrv/encoder_for_aptxhd/src/SubbandFunctions.h b/system/embdrv/encoder_for_aptxhd/src/SubbandFunctions.h index 84cd2dd42ddb341806265ef6e1e8c802c65de2f2..ebf8f4853417d88cb8467d3a3e8eb5db1e23dd09 100644 --- a/system/embdrv/encoder_for_aptxhd/src/SubbandFunctions.h +++ b/system/embdrv/encoder_for_aptxhd/src/SubbandFunctions.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Subband processing consists of: @@ -10,174 +25,163 @@ #ifndef SUBBANDFUNCTIONS_H #define SUBBANDFUNCTIONS_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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]; +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 indices 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 indices 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 = (int32_t)((uint32_t)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 +#pragma GCC visibility pop #endif -#endif //SUBBANDFUNCTIONS_H +#endif // SUBBANDFUNCTIONS_H diff --git a/system/embdrv/encoder_for_aptxhd/src/SubbandFunctionsCommon.h b/system/embdrv/encoder_for_aptxhd/src/SubbandFunctionsCommon.h index 618d439919722e1e6e859459a8154d20a5a7f2e4..6a6d0264d72da5821ba27e8c44c496a3cde9f359 100644 --- a/system/embdrv/encoder_for_aptxhd/src/SubbandFunctionsCommon.h +++ b/system/embdrv/encoder_for_aptxhd/src/SubbandFunctionsCommon.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * Subband processing consists of: @@ -10,511 +25,489 @@ #ifndef SUBBANDFUNCTIONSCOMMON_H #define SUBBANDFUNCTIONSCOMMON_H +enum reg64_reg { reg64_H = 1, reg64_L = 0 }; -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); +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 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; +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 +/* 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 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 indices */ + 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 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 indices */ + 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; +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 indices */ + 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 +#endif // SUBBANDFUNCTIONSCOMMON_H diff --git a/system/embdrv/encoder_for_aptxhd/src/SyncInserter.h b/system/embdrv/encoder_for_aptxhd/src/SyncInserter.h index f393a0d223e22085712837ea012f4231d53b77df..8bad975a24da99236e30aa6ffc8509007cfc2af5 100644 --- a/system/embdrv/encoder_for_aptxhd/src/SyncInserter.h +++ b/system/embdrv/encoder_for_aptxhd/src/SyncInserter.h @@ -1,3 +1,18 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ /*------------------------------------------------------------------------------ * * All declarations relevant for the SyncInserter class. This class exposes a @@ -9,106 +24,100 @@ #ifndef SYNCINSERTER_H #define SYNCINSERTER_H #ifdef _GCC - #pragma GCC visibility push(hidden) +#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; +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 +#pragma GCC visibility pop #endif -#endif //SYNCINSERTER_H +#endif // SYNCINSERTER_H diff --git a/system/embdrv/encoder_for_aptxhd/src/aptXHDbtenc.c b/system/embdrv/encoder_for_aptxhd/src/aptXHDbtenc.c index 9eac1a378e3574338054a8b82c1e1cb69be08ccd..8d93d9d37c70317d879263861ded8077cf8263e6 100644 --- a/system/embdrv/encoder_for_aptxhd/src/aptXHDbtenc.c +++ b/system/embdrv/encoder_for_aptxhd/src/aptXHDbtenc.c @@ -1,179 +1,184 @@ -#include "AptxParameters.h" -#include "AptxTables.h" +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "aptXHDbtenc.h" + #include "AptxEncoder.h" -#include "SyncInserter.h" +#include "AptxParameters.h" +#include "AptxTables.h" #include "CodewordPacker.h" +#include "SyncInserter.h" #include "swversion.h" +typedef struct aptxhdbtenc_t { + /* m_endian should either be 0 (little endian) or 8 (big endian). */ + int32_t m_endian; -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; - /* 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 + /* 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; + /* 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)); +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}; + +static 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 const char* aptxhdbtenc_version() -{ - return (swversion); -} +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; + + 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 (int 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 (int t = 0; t < 48; t++) { + encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.buffer[t] = 0; + } -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; + 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 (int k = 0; k < 24; k++) { + encode_dat->m_SubbandData[i].m_ZeroCoeffData.m_zeroCoeff[k] = 0; } - } - 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; + // 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; +} - //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]); +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; - //Insert the autosync information into the stereo quantised codes - xbtEncinsertSync(&state->m_encoderData[0], &state->m_encoderData[1], &state->m_syncWordPhase); + // 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]); - aptxhdPostEncode(&state->m_encoderData[0]); - aptxhdPostEncode(&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); - //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; + aptxhdPostEncode(&state->m_encoderData[0]); + aptxhdPostEncode(&state->m_encoderData[1]); - tmp_reg = packCodeword(&state->m_encoderData[1]); - buffer[1] = (int32_t)tmp_reg; + // Pack the (possibly adjusted) codes into a 24-bit codeword per channel + buffer[0] = packCodeword(&state->m_encoderData[0]); + buffer[1] = packCodeword(&state->m_encoderData[1]); - return 0; + return 0; } diff --git a/system/embdrv/encoder_for_aptxhd/src/swversion.h b/system/embdrv/encoder_for_aptxhd/src/swversion.h index 7ca62d488455f06f894725e0be5eec523ebb4799..a55b211377d60599f390344f499c8362a80a7a6a 100644 --- a/system/embdrv/encoder_for_aptxhd/src/swversion.h +++ b/system/embdrv/encoder_for_aptxhd/src/swversion.h @@ -1,8 +1,21 @@ +/** + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #ifndef SWVERSION_H #define SWVERSION_H +static const char* swversion = "1.0.0"; -const char* swversion = "1.0.0"; - - -#endif //SWVERSION_H +#endif // SWVERSION_H diff --git a/system/embdrv/tests/Android.bp b/system/embdrv/tests/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..4b57d769fc06141a106bb8a85acb9afcc45aadca --- /dev/null +++ b/system/embdrv/tests/Android.bp @@ -0,0 +1,35 @@ +cc_test { + name: "libaptx_enc_tests", + defaults: [ + "mts_defaults", + ], + test_suites: ["device-tests"], + host_supported: true, + test_options: { + unit_test: true, + }, + srcs: [ "src/aptx.cc" ], + whole_static_libs: [ "libaptx_enc" ], + sanitize: { + address: true, + cfi: true, + }, +} + +cc_test { + name: "libaptxhd_enc_tests", + defaults: [ + "mts_defaults", + ], + test_suites: ["device-tests"], + host_supported: true, + test_options: { + unit_test: true, + }, + srcs: [ "src/aptxhd.cc" ], + whole_static_libs: [ "libaptxhd_enc" ], + sanitize: { + address: true, + cfi: true, + }, +} diff --git a/system/embdrv/tests/src/aptx.cc b/system/embdrv/tests/src/aptx.cc new file mode 100644 index 0000000000000000000000000000000000000000..bc2736347b7b0583aa99f9ff0ea8d036a120311c --- /dev/null +++ b/system/embdrv/tests/src/aptx.cc @@ -0,0 +1,79 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <gtest/gtest.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <fstream> +#include <iostream> + +#include "aptXbtenc.h" + +#define BYTES_PER_CODEWORD 16 + +class LibAptxEncTest : public ::testing::Test { + private: + void* aptxbtenc = nullptr; + + protected: + void SetUp() override { + aptxbtenc = malloc(SizeofAptxbtenc()); + ASSERT_NE(aptxbtenc, nullptr); + ASSERT_EQ(aptxbtenc_init(aptxbtenc, 0), 0); + } + + void TearDown() override { free(aptxbtenc); } + + void codeword_cmp(const uint16_t pcm[8], const uint32_t codeword) { + uint32_t pcmL[4]; + uint32_t pcmR[4]; + for (size_t i = 0; i < 4; i++) { + pcmL[i] = pcm[0]; + pcmR[i] = pcm[1]; + pcm += 2; + } + uint32_t encoded_sample; + aptxbtenc_encodestereo(aptxbtenc, &pcmL, &pcmR, &encoded_sample); + ASSERT_EQ(encoded_sample, codeword); + } +}; + +TEST_F(LibAptxEncTest, encoder_size) { ASSERT_EQ(SizeofAptxbtenc(), 5008); } + +TEST_F(LibAptxEncTest, encode_fake_data) { + const char input[] = + "012345678901234567890123456789012345678901234567890123456789012345678901" + "23456789"; + const uint32_t aptx_codeword[] = {1270827967, 134154239, 670640127, + 1280265295, 2485752873}; + + ASSERT_EQ((sizeof(input) - 1) % BYTES_PER_CODEWORD, 0); + ASSERT_EQ((sizeof(input) - 1) / BYTES_PER_CODEWORD, + sizeof(aptx_codeword) / sizeof(uint32_t)); + + size_t idx = 0; + + uint16_t pcm[8]; + + while (idx * BYTES_PER_CODEWORD < sizeof(input) - 1) { + memcpy(pcm, input + idx * BYTES_PER_CODEWORD, BYTES_PER_CODEWORD); + codeword_cmp(pcm, aptx_codeword[idx]); + ++idx; + } +} diff --git a/system/embdrv/tests/src/aptxhd.cc b/system/embdrv/tests/src/aptxhd.cc new file mode 100644 index 0000000000000000000000000000000000000000..f1a7722ef0b100a4fd0b3862ed91dbeea26185e9 --- /dev/null +++ b/system/embdrv/tests/src/aptxhd.cc @@ -0,0 +1,82 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <gtest/gtest.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <fstream> +#include <iostream> + +#include "aptXHDbtenc.h" + +#define BYTES_PER_CODEWORD 24 + +class LibAptxHdEncTest : public ::testing::Test { + private: + protected: + void* aptxhdbtenc = nullptr; + void SetUp() override { + aptxhdbtenc = malloc(SizeofAptxhdbtenc()); + ASSERT_NE(aptxhdbtenc, nullptr); + ASSERT_EQ(aptxhdbtenc_init(aptxhdbtenc, 0), 0); + } + + void TearDown() override { free(aptxhdbtenc); } + + void codeword_cmp(const uint8_t p[BYTES_PER_CODEWORD], + const uint32_t codeword[2]) { + uint32_t pcmL[4]; + uint32_t pcmR[4]; + for (size_t i = 0; i < 4; i++) { + pcmL[i] = ((p[0] << 0) | (p[1] << 8) | (((int8_t)p[2]) << 16)); + p += 3; + pcmR[i] = ((p[0] << 0) | (p[1] << 8) | (((int8_t)p[2]) << 16)); + p += 3; + } + uint32_t encoded_sample[2]; + aptxhdbtenc_encodestereo(aptxhdbtenc, &pcmL, &pcmR, (void*)encoded_sample); + + ASSERT_EQ(encoded_sample[0], codeword[0]); + ASSERT_EQ(encoded_sample[1], codeword[1]); + } +}; + +TEST_F(LibAptxHdEncTest, encoder_size) { ASSERT_EQ(SizeofAptxhdbtenc(), 5256); } + +TEST_F(LibAptxHdEncTest, encode_fake_data) { + const char input[] = + "012345678901234567890123456789012345678901234567890123456789012345678901" + "234567890123456789012345678901234567890123456789"; + const uint32_t aptxhd_codeword[] = {7585535, 7585535, 32767, 32767, + 557055, 557027, 7586105, 7586109, + 9748656, 10764446}; + + ASSERT_EQ((sizeof(input) - 1) % BYTES_PER_CODEWORD, 0); + ASSERT_EQ((sizeof(input) - 1) / BYTES_PER_CODEWORD, + sizeof(aptxhd_codeword) / sizeof(uint32_t) / 2); + + size_t idx = 0; + + uint8_t pcm[BYTES_PER_CODEWORD]; + while (idx * BYTES_PER_CODEWORD < sizeof(input) - 1) { + memcpy(pcm, input + idx * BYTES_PER_CODEWORD, BYTES_PER_CODEWORD); + codeword_cmp(pcm, aptxhd_codeword + idx * 2); + ++idx; + } +} diff --git a/system/stack/Android.bp b/system/stack/Android.bp index af78d58a1405028f712674322bbe100d875ec040..e8d95cd5acc9e41823470523df143dd59520fdc7 100644 --- a/system/stack/Android.bp +++ b/system/stack/Android.bp @@ -208,6 +208,8 @@ cc_library_static { whole_static_libs: [ "libldacBT_abr", "libldacBT_enc", + "libaptx_enc", + "libaptxhd_enc", ], host_supported: true, min_sdk_version: "Tiramisu" @@ -626,11 +628,7 @@ cc_test { "packages/modules/Bluetooth/system/stack/include", ], srcs: [ - "a2dp/a2dp_vendor_aptx_encoder.cc", - "a2dp/a2dp_vendor_aptx_hd_encoder.cc", "a2dp/a2dp_vendor_ldac_decoder.cc", - "test/a2dp/a2dp_vendor_aptx_encoder_test.cc", - "test/a2dp/a2dp_vendor_aptx_hd_encoder_test.cc", "test/a2dp/a2dp_vendor_ldac_decoder_test.cc", "test/a2dp/misc_fake.cc", ], diff --git a/system/stack/a2dp/a2dp_vendor.cc b/system/stack/a2dp/a2dp_vendor.cc index 759fc431347a10d57cb9ad5bf09f15e0dafaba77..edca1531792dcfb5469a80b1a2924eadcc364f7c 100644 --- a/system/stack/a2dp/a2dp_vendor.cc +++ b/system/stack/a2dp/a2dp_vendor.cc @@ -660,16 +660,3 @@ std::string A2DP_VendorCodecInfoString(const uint8_t* p_codec_info) { return "Unsupported codec vendor_id: " + loghex(vendor_id) + " codec_id: " + loghex(codec_id); } - -void* A2DP_VendorCodecLoadExternalLib(const std::string& lib_name, - const std::string& friendly_name) { - void* lib_handle = dlopen(lib_name.c_str(), RTLD_NOW); - if (lib_handle == NULL) { - LOG(ERROR) << __func__ - << ": Failed to load codec library: " << friendly_name - << ". Err: [" << dlerror() << "]"; - return nullptr; - } - LOG(INFO) << __func__ << ": Codec library loaded: " << friendly_name; - return lib_handle; -} diff --git a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc index 92463f58831c884377de2e75d6055d0f145e053c..5a3785c0f944fe3413d58d6b9c22ead8423a9f48 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_encoder.cc @@ -25,6 +25,7 @@ #include "a2dp_vendor.h" #include "a2dp_vendor_aptx.h" +#include "aptXbtenc.h" #include "common/time_util.h" #include "osi/include/allocator.h" #include "osi/include/log.h" @@ -35,18 +36,11 @@ // Encoder for aptX Source Codec // -// -// The aptX encoder shared library, and the functions to use -// -const std::string APTX_ENCODER_LIB_NAME = "libaptX_encoder.so"; -static void* aptx_encoder_lib_handle = NULL; - -static const std::string APTX_ENCODER_INIT_NAME = "aptxbtenc_init"; -static const std::string APTX_ENCODER_ENCODE_STEREO_NAME = - "aptxbtenc_encodestereo"; -static const std::string APTX_ENCODER_SIZEOF_PARAMS_NAME = "SizeofAptxbtenc"; - -static tAPTX_API aptx_api; +static const tAPTX_API aptx_api = { + .init_func = aptxbtenc_init, + .encode_stereo_func = aptxbtenc_encodestereo, + .sizeof_params_func = SizeofAptxbtenc, +}; // offset #if (BTA_AV_CO_CP_SCMS_T == TRUE) @@ -56,10 +50,6 @@ static tAPTX_API aptx_api; #define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET - AVDT_MEDIA_HDR_SIZE) #endif -#define LOAD_APTX_SYMBOL(symbol_name, api_type) \ - LOAD_CODEC_SYMBOL("AptX", aptx_encoder_lib_handle, \ - A2DP_VendorUnloadEncoderAptx, symbol_name, api_type) - #define A2DP_APTX_MAX_PCM_BYTES_PER_READ 4096 typedef struct { @@ -120,39 +110,17 @@ static size_t aptx_encode_16bit(tAPTX_FRAMING_PARAMS* framing_params, * ******************************************************************************/ tLOADING_CODEC_STATUS A2DP_VendorLoadEncoderAptx(void) { - if (aptx_encoder_lib_handle != NULL) return LOAD_SUCCESS; // Already loaded - - // Open the encoder library - aptx_encoder_lib_handle = - A2DP_VendorCodecLoadExternalLib(APTX_ENCODER_LIB_NAME, "AptX encoder"); - - if (!aptx_encoder_lib_handle) return LOAD_ERROR_MISSING_CODEC; - - aptx_api.init_func = - LOAD_APTX_SYMBOL(APTX_ENCODER_INIT_NAME, tAPTX_ENCODER_INIT); - - aptx_api.encode_stereo_func = LOAD_APTX_SYMBOL( - APTX_ENCODER_ENCODE_STEREO_NAME, tAPTX_ENCODER_ENCODE_STEREO); - - aptx_api.sizeof_params_func = LOAD_APTX_SYMBOL( - APTX_ENCODER_SIZEOF_PARAMS_NAME, tAPTX_ENCODER_SIZEOF_PARAMS); - + // Nothing to do - the library is statically linked return LOAD_SUCCESS; } bool A2DP_VendorCopyAptxApi(tAPTX_API& external_api) { - if (aptx_encoder_lib_handle == NULL) return false; // not loaded external_api = aptx_api; return true; } void A2DP_VendorUnloadEncoderAptx(void) { - memset(&aptx_api, 0, sizeof(aptx_api)); - - if (aptx_encoder_lib_handle != NULL) { - dlclose(aptx_encoder_lib_handle); - aptx_encoder_lib_handle = NULL; - } + // nothing to do } void a2dp_vendor_aptx_encoder_init( diff --git a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc index f3dd9e4ce58b71a080c35685917c51a8eeb379db..749ffdf463c215f37d716f9f75b071f8427814ea 100644 --- a/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc +++ b/system/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc @@ -25,6 +25,7 @@ #include "a2dp_vendor.h" #include "a2dp_vendor_aptx_hd.h" +#include "aptXHDbtenc.h" #include "common/time_util.h" #include "osi/include/allocator.h" #include "osi/include/log.h" @@ -35,19 +36,11 @@ // Encoder for aptX-HD Source Codec // -// -// The aptX-HD encoder shared library, and the functions to use -// -static const std::string APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so"; -static void* aptx_hd_encoder_lib_handle = NULL; - -static const std::string APTX_HD_ENCODER_INIT_NAME = "aptxhdbtenc_init"; -static const std::string APTX_HD_ENCODER_ENCODE_STEREO_NAME = - "aptxhdbtenc_encodestereo"; -static const std::string APTX_HD_ENCODER_SIZEOF_PARAMS_NAME = - "SizeofAptxhdbtenc"; - -static tAPTX_HD_API aptx_hd_api; +static const tAPTX_HD_API aptx_hd_api = { + .init_func = aptxhdbtenc_init, + .encode_stereo_func = aptxhdbtenc_encodestereo, + .sizeof_params_func = SizeofAptxhdbtenc, +}; // offset #if (BTA_AV_CO_CP_SCMS_T == TRUE) @@ -56,10 +49,6 @@ static tAPTX_HD_API aptx_hd_api; #define A2DP_APTX_HD_OFFSET AVDT_MEDIA_OFFSET #endif -#define LOAD_APTX_HD_SYMBOL(symbol_name, api_type) \ - LOAD_CODEC_SYMBOL("AptXHd", aptx_hd_encoder_lib_handle, \ - A2DP_VendorUnloadEncoderAptxHd, symbol_name, api_type) - #define A2DP_APTX_HD_MAX_PCM_BYTES_PER_READ 4096 typedef struct { @@ -121,39 +110,17 @@ static size_t aptx_hd_encode_24bit(tAPTX_HD_FRAMING_PARAMS* framing_params, * ******************************************************************************/ tLOADING_CODEC_STATUS A2DP_VendorLoadEncoderAptxHd(void) { - if (aptx_hd_encoder_lib_handle != NULL) - return LOAD_SUCCESS; // Already loaded - - // Open the encoder library - aptx_hd_encoder_lib_handle = A2DP_VendorCodecLoadExternalLib( - APTX_HD_ENCODER_LIB_NAME, "AptX-HD encoder"); - if (!aptx_hd_encoder_lib_handle) return LOAD_ERROR_MISSING_CODEC; - - aptx_hd_api.init_func = - LOAD_APTX_HD_SYMBOL(APTX_HD_ENCODER_INIT_NAME, tAPTX_HD_ENCODER_INIT); - - aptx_hd_api.encode_stereo_func = LOAD_APTX_HD_SYMBOL( - APTX_HD_ENCODER_ENCODE_STEREO_NAME, tAPTX_HD_ENCODER_ENCODE_STEREO); - - aptx_hd_api.sizeof_params_func = LOAD_APTX_HD_SYMBOL( - APTX_HD_ENCODER_SIZEOF_PARAMS_NAME, tAPTX_HD_ENCODER_SIZEOF_PARAMS); - + // Nothing to do - the library is statically linked return LOAD_SUCCESS; } bool A2DP_VendorCopyAptxHdApi(tAPTX_HD_API& external_api) { - if (aptx_hd_encoder_lib_handle == NULL) return false; // not loaded external_api = aptx_hd_api; return true; } void A2DP_VendorUnloadEncoderAptxHd(void) { - memset(&aptx_hd_api, 0, sizeof(aptx_hd_api)); - - if (aptx_hd_encoder_lib_handle != NULL) { - dlclose(aptx_hd_encoder_lib_handle); - aptx_hd_encoder_lib_handle = NULL; - } + // nothing to do } void a2dp_vendor_aptx_hd_encoder_init( diff --git a/system/stack/include/a2dp_vendor.h b/system/stack/include/a2dp_vendor.h index f2b6feb9bfff298f346687494b3a308e1f358fd6..b8bf9de3760869024209ab6d2f3f1a0a002cba25 100644 --- a/system/stack/include/a2dp_vendor.h +++ b/system/stack/include/a2dp_vendor.h @@ -220,25 +220,4 @@ bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index, // Returns a string describing the codec information. std::string A2DP_VendorCodecInfoString(const uint8_t* p_codec_info); -// Try to dlopen external codec library -// -// |lib_name| is the name of the library to load -// |friendly_name| is only use for logging purpose -// Return pointer to the handle if the library is successfully dlopen, -// nullptr otherwise -void* A2DP_VendorCodecLoadExternalLib(const std::string& lib_name, - const std::string& friendly_name); - -#define LOAD_CODEC_SYMBOL(codec_name, handle, error_fn, symbol_name, api_type) \ - ({ \ - void* load_sym = dlsym(handle, symbol_name.c_str()); \ - if (load_sym == NULL) { \ - LOG_ERROR("Cannot find function '%s' in the '%s' encoder library: %s", \ - symbol_name.c_str(), codec_name, dlerror()); \ - error_fn(); \ - return LOAD_ERROR_VERSION_MISMATCH; \ - } \ - (api_type) load_sym; \ - }) - #endif // A2DP_VENDOR_H diff --git a/system/stack/test/a2dp/a2dp_vendor_aptx_encoder_test.cc b/system/stack/test/a2dp/a2dp_vendor_aptx_encoder_test.cc deleted file mode 100644 index 8e77a96afdfe933474b8539d251647ce4620ced1..0000000000000000000000000000000000000000 --- a/system/stack/test/a2dp/a2dp_vendor_aptx_encoder_test.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "aptx_encoder_test" - -#include "a2dp_vendor_aptx_encoder.h" - -#include <base/logging.h> -#include <gtest/gtest.h> -#include <stdio.h> - -#include <cstdint> - -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/test/AllocationTestHarness.h" - -extern void allocation_tracker_uninit(void); - -class A2dpAptxTest : public AllocationTestHarness { - protected: - void SetUp() override { AllocationTestHarness::SetUp(); } - - void TearDown() override { AllocationTestHarness::TearDown(); } -}; - -TEST_F(A2dpAptxTest, CheckLoadLibrary) { - tLOADING_CODEC_STATUS aptx_support = A2DP_VendorLoadEncoderAptx(); - if (aptx_support == LOAD_ERROR_MISSING_CODEC) { - LOG_WARN("Aptx library not found, ignored test"); - return; - } - // Loading is either success or missing library. Version mismatch is not - // allowed - ASSERT_EQ(aptx_support, LOAD_SUCCESS); -} - -TEST_F(A2dpAptxTest, EncodePacket) { - tLOADING_CODEC_STATUS aptx_support = A2DP_VendorLoadEncoderAptx(); - if (aptx_support == LOAD_ERROR_MISSING_CODEC) { - LOG_WARN("Aptx library not found, ignored test"); - return; - } - // Loading is either success or missing library. Wrong symbol is not allowed - ASSERT_EQ(aptx_support, LOAD_SUCCESS); - - tAPTX_API aptx_api; - ASSERT_TRUE(A2DP_VendorCopyAptxApi(aptx_api)); - - ASSERT_EQ(aptx_api.sizeof_params_func(), 5008); - void* handle = osi_malloc(aptx_api.sizeof_params_func()); - ASSERT_TRUE(handle != NULL); - aptx_api.init_func(handle, 0); - - size_t pcm_bytes_encoded = 0; - size_t frame = 0; - const uint16_t *data16_in = (uint16_t *)"01234567890123456789012345678901234567890123456789012345678901234567890123456789"; - uint8_t data_out[20]; - const uint8_t expected_data_out[20] = {75, 191, 75, 191, 7, 255, 7, - 255, 39, 255, 39, 249, 76, 79, - 76, 79, 148, 41, 148, 41}; - - size_t data_out_index = 0; - - for (size_t samples = 0; - samples < strlen((char*)data16_in) / 16; // 16 bit encode - samples++) { - uint32_t pcmL[4]; - uint32_t pcmR[4]; - uint16_t encoded_sample[2]; - for (size_t i = 0, j = frame; i < 4; i++, j++) { - pcmL[i] = (uint16_t) * (data16_in + (2 * j)); - pcmR[i] = (uint16_t) * (data16_in + ((2 * j) + 1)); - } - - aptx_api.encode_stereo_func(handle, &pcmL, &pcmR, &encoded_sample); - - data_out[data_out_index + 0] = (uint8_t)((encoded_sample[0] >> 8) & 0xff); - data_out[data_out_index + 1] = (uint8_t)((encoded_sample[0] >> 0) & 0xff); - data_out[data_out_index + 2] = (uint8_t)((encoded_sample[1] >> 8) & 0xff); - data_out[data_out_index + 3] = (uint8_t)((encoded_sample[1] >> 0) & 0xff); - frame += 4; - pcm_bytes_encoded += 16; - data_out_index += 4; - } - - ASSERT_EQ(sizeof(expected_data_out), data_out_index); - ASSERT_EQ(0, memcmp(data_out, expected_data_out, sizeof(expected_data_out))); - - osi_free(handle); -} diff --git a/system/stack/test/a2dp/a2dp_vendor_aptx_hd_encoder_test.cc b/system/stack/test/a2dp/a2dp_vendor_aptx_hd_encoder_test.cc deleted file mode 100644 index 9f89bf34de778b4cf15d292218a21baf5600b94c..0000000000000000000000000000000000000000 --- a/system/stack/test/a2dp/a2dp_vendor_aptx_hd_encoder_test.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "aptx_encoder_test" - -#include "a2dp_vendor_aptx_hd_encoder.h" - -#include <base/logging.h> -#include <gtest/gtest.h> -#include <stdio.h> - -#include <cstdint> - -#include "osi/include/allocator.h" -#include "osi/include/log.h" -#include "osi/test/AllocationTestHarness.h" - -extern void allocation_tracker_uninit(void); - -class A2dpAptxHdTest : public AllocationTestHarness { - protected: - void SetUp() override { AllocationTestHarness::SetUp(); } - - void TearDown() override { AllocationTestHarness::TearDown(); } -}; - -TEST_F(A2dpAptxHdTest, CheckLoadLibrary) { - tLOADING_CODEC_STATUS aptx_support = A2DP_VendorLoadEncoderAptxHd(); - if (aptx_support == LOAD_ERROR_MISSING_CODEC) { - LOG_WARN("Aptx Hd library not found, ignored test"); - return; - } - // Loading is either success or missing library. Version mismatch is not - // allowed - ASSERT_EQ(aptx_support, LOAD_SUCCESS); -} - -TEST_F(A2dpAptxHdTest, EncodePacket) { - tLOADING_CODEC_STATUS aptx_support = A2DP_VendorLoadEncoderAptxHd(); - if (aptx_support == LOAD_ERROR_MISSING_CODEC) { - LOG_WARN("Aptx Hd library not found, ignored test"); - return; - } - // Loading is either success or missing library. Wrong symbol is not allowed - ASSERT_EQ(aptx_support, LOAD_SUCCESS); - - tAPTX_HD_API aptx_hd_api; - ASSERT_TRUE(A2DP_VendorCopyAptxHdApi(aptx_hd_api)); - - ASSERT_EQ(aptx_hd_api.sizeof_params_func(), 5256); - void* handle = osi_malloc(aptx_hd_api.sizeof_params_func()); - ASSERT_TRUE(handle != NULL); - aptx_hd_api.init_func(handle, 0); - - size_t pcm_bytes_encoded = 0; - const uint32_t *data32_in = (uint32_t *)"012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; - const uint8_t* p = (const uint8_t*)(data32_in); - uint8_t data_out[30]; - const uint8_t expected_data_out[30] = {115, 190, 255, 115, 190, 255, 0, 127, - 255, 0, 127, 255, 8, 127, 255, 8, - 127, 227, 115, 193, 57, 115, 193, 61, - 148, 192, 176, 164, 64, 158}; - - size_t data_out_index = 0; - - for (size_t samples = 0; - samples < strlen((char*)data32_in) / 24; // 24 bit encode - samples++) { - uint32_t pcmL[4]; - uint32_t pcmR[4]; - uint32_t encoded_sample[2]; - // Expand from AUDIO_FORMAT_PCM_24_BIT_PACKED data (3 bytes per sample) - // into AUDIO_FORMAT_PCM_8_24_BIT (4 bytes per sample). - for (size_t i = 0; i < 4; i++) { - pcmL[i] = ((p[0] << 0) | (p[1] << 8) | (((int8_t)p[2]) << 16)); - p += 3; - pcmR[i] = ((p[0] << 0) | (p[1] << 8) | (((int8_t)p[2]) << 16)); - p += 3; - } - - aptx_hd_api.encode_stereo_func(handle, &pcmL, &pcmR, &encoded_sample); - - uint8_t* encoded_ptr = (uint8_t*)&encoded_sample[0]; - data_out[data_out_index + 0] = *(encoded_ptr + 2); - data_out[data_out_index + 1] = *(encoded_ptr + 1); - data_out[data_out_index + 2] = *(encoded_ptr + 0); - data_out[data_out_index + 3] = *(encoded_ptr + 6); - data_out[data_out_index + 4] = *(encoded_ptr + 5); - data_out[data_out_index + 5] = *(encoded_ptr + 4); - - pcm_bytes_encoded += 24; - data_out_index += 6; - } - - // for (size_t i =0; i < data_out_index; i++) { - // LOG_ERROR("DATA %zu is %hu", i, data_out[i]); - // } - - ASSERT_EQ(sizeof(expected_data_out), data_out_index); - ASSERT_EQ(0, memcmp(data_out, expected_data_out, sizeof(expected_data_out))); - - osi_free(handle); -}