1 /**
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "aptXbtenc.h"
17
18 #include "AptxEncoder.h"
19 #include "AptxParameters.h"
20 #include "AptxTables.h"
21 #include "CodewordPacker.h"
22 #include "SyncInserter.h"
23 #include "swversion.h"
24
25 typedef struct aptxbtenc_t {
26 /* m_endian should either be 0 (little endian) or 8 (big endian). */
27 int32_t m_endian;
28
29 /* m_sync_mode is an enumerated type and will be
30 0 (stereo sync),
31 1 (for dual mono sync), or
32 2 (for dual channel with no autosync).
33 */
34 int32_t m_sync_mode;
35
36 /* Autosync inserter & Checker for use with the stereo aptX codec. */
37 /* The current phase of the sync word insertion (7 down to 0) */
38 uint32_t m_syncWordPhase;
39
40 /* Stereo channel aptX encoder (annotated to produce Kalimba test vectors
41 * for it's I/O. This will process valid PCM from a WAV file). */
42 /* Each Encoder_data structure requires 1592 bytes */
43 Encoder_data m_encoderData[2];
44 Qmf_storage m_qmf_l;
45 Qmf_storage m_qmf_r;
46 } aptxbtenc;
47
48 /* Log to linear lookup table used in inverse quantiser*/
49 /* Size of Table: 32*4 = 128 bytes */
50 static const int32_t IQuant_tableLogT[32] = {
51 16384 * 256, 16744 * 256, 17112 * 256, 17488 * 256, 17864 * 256, 18256 * 256, 18656 * 256,
52 19064 * 256, 19480 * 256, 19912 * 256, 20344 * 256, 20792 * 256, 21248 * 256, 21712 * 256,
53 22192 * 256, 22672 * 256, 23168 * 256, 23680 * 256, 24200 * 256, 24728 * 256, 25264 * 256,
54 25824 * 256, 26384 * 256, 26968 * 256, 27552 * 256, 28160 * 256, 28776 * 256, 29408 * 256,
55 30048 * 256, 30704 * 256, 31376 * 256, 32064 * 256};
56
clearmem(void * mem,int32_t sz)57 static void clearmem(void* mem, int32_t sz) {
58 int8_t* m = (int8_t*)mem;
59 int32_t i = 0;
60 for (; i < sz; i++) {
61 *m = 0;
62 m++;
63 }
64 }
65
SizeofAptxbtenc(void)66 APTXBTENCEXPORT int SizeofAptxbtenc(void) { return sizeof(aptxbtenc); }
67
aptxbtenc_version()68 APTXBTENCEXPORT const char* aptxbtenc_version() { return swversion; }
69
aptxbtenc_init(void * _state,short endian)70 APTXBTENCEXPORT int aptxbtenc_init(void* _state, short endian) {
71 aptxbtenc* state = (aptxbtenc*)_state;
72 int32_t j = 0;
73 int32_t k;
74 int32_t t;
75
76 clearmem(_state, sizeof(aptxbtenc));
77
78 if (state == 0) {
79 return 1;
80 }
81 state->m_syncWordPhase = 7L;
82
83 if (endian == 0) {
84 state->m_endian = 0;
85 } else {
86 state->m_endian = 8;
87 }
88
89 /* default setting should be stereo autosync,
90 for backwards-compatibility with legacy applications that use this library */
91 state->m_sync_mode = stereo;
92
93 for (j = 0; j < 2; j++) {
94 Encoder_data* encode_dat = &state->m_encoderData[j];
95 uint32_t i;
96
97 /* Create a quantiser and subband processor for each subband */
98 for (i = LL; i <= HH; i++) {
99 encode_dat->m_codewordHistory = 0L;
100
101 encode_dat->m_qdata[i].thresholdTablePtr = subbandParameters[i].threshTable;
102 encode_dat->m_qdata[i].thresholdTablePtr_sl1 = subbandParameters[i].threshTable_sl1;
103 encode_dat->m_qdata[i].ditherTablePtr = subbandParameters[i].dithTable;
104 encode_dat->m_qdata[i].minusLambdaDTable = subbandParameters[i].minusLambdaDTable;
105 encode_dat->m_qdata[i].codeBits = subbandParameters[i].numBits;
106 encode_dat->m_qdata[i].qCode = 0L;
107 encode_dat->m_qdata[i].altQcode = 0L;
108 encode_dat->m_qdata[i].distPenalty = 0L;
109
110 /* initialisation of inverseQuantiser data */
111 encode_dat->m_SubbandData[i].m_iqdata.thresholdTablePtr = subbandParameters[i].threshTable;
112 encode_dat->m_SubbandData[i].m_iqdata.thresholdTablePtr_sl1 =
113 subbandParameters[i].threshTable_sl1;
114 encode_dat->m_SubbandData[i].m_iqdata.ditherTablePtr_sf1 = subbandParameters[i].dithTable_sh1;
115 encode_dat->m_SubbandData[i].m_iqdata.incrTablePtr = subbandParameters[i].incrTable;
116 encode_dat->m_SubbandData[i].m_iqdata.maxLogDelta = subbandParameters[i].maxLogDelta;
117 encode_dat->m_SubbandData[i].m_iqdata.minLogDelta = subbandParameters[i].minLogDelta;
118 encode_dat->m_SubbandData[i].m_iqdata.delta = 0;
119 encode_dat->m_SubbandData[i].m_iqdata.logDelta = 0;
120 encode_dat->m_SubbandData[i].m_iqdata.invQ = 0;
121 encode_dat->m_SubbandData[i].m_iqdata.iquantTableLogPtr = &IQuant_tableLogT[0];
122
123 // Initializing data for predictor filter
124 encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.modulo =
125 subbandParameters[i].numZeros;
126
127 for (t = 0; t < 48; t++) {
128 encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.buffer[t] = 0;
129 }
130
131 encode_dat->m_SubbandData[i].m_predData.m_zeroDelayLine.pointer = 0;
132 /* Initialise the previous zero filter output and predictor output to zero
133 */
134 encode_dat->m_SubbandData[i].m_predData.m_zeroVal = 0L;
135 encode_dat->m_SubbandData[i].m_predData.m_predVal = 0L;
136 encode_dat->m_SubbandData[i].m_predData.m_numZeros = subbandParameters[i].numZeros;
137 /* Initialise the contents of the pole data delay line to zero */
138 encode_dat->m_SubbandData[i].m_predData.m_poleDelayLine[0] = 0L;
139 encode_dat->m_SubbandData[i].m_predData.m_poleDelayLine[1] = 0L;
140
141 for (k = 0; k < 24; k++) {
142 encode_dat->m_SubbandData[i].m_ZeroCoeffData.m_zeroCoeff[k] = 0;
143 }
144 // Initializing data for zerocoeff update function.
145 encode_dat->m_SubbandData[i].m_ZeroCoeffData.m_numZeros = subbandParameters[i].numZeros;
146
147 /* Initializing data for PoleCoeff Update function.
148 * Fill the adaptation delay line with +1 initially */
149 encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleAdaptDelayLine.s32 = 0x00010001;
150
151 /* Zero the pole coefficients */
152 encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleCoeff[0] = 0L;
153 encode_dat->m_SubbandData[i].m_PoleCoeffData.m_poleCoeff[1] = 0L;
154 }
155 }
156 return 0;
157 }
158
aptxbtenc_setsync_mode(void * _state,int32_t sync_mode)159 APTXBTENCEXPORT int aptxbtenc_setsync_mode(void* _state, int32_t sync_mode) {
160 aptxbtenc* state = (aptxbtenc*)_state;
161 state->m_sync_mode = sync_mode;
162
163 return 0;
164 }
165
aptxbtenc_encodestereo(void * _state,void * _pcmL,void * _pcmR,void * _buffer)166 APTXBTENCEXPORT int aptxbtenc_encodestereo(void* _state, void* _pcmL, void* _pcmR, void* _buffer) {
167 aptxbtenc* state = (aptxbtenc*)_state;
168 int32_t* pcmL = (int32_t*)_pcmL;
169 int32_t* pcmR = (int32_t*)_pcmR;
170 int16_t* buffer = (int16_t*)_buffer;
171 int16_t tmp_reg;
172 int16_t tmp_out;
173 // Feed the PCM to the dual aptX encoders
174 aptxEncode(pcmL, &state->m_qmf_l, &state->m_encoderData[0]);
175 aptxEncode(pcmR, &state->m_qmf_r, &state->m_encoderData[1]);
176
177 // only insert sync information if we are not in non-autosync mode.
178 // The Non-autosync mode changes only take effect in the packCodeword()
179 // function.
180 if (state->m_sync_mode != no_sync) {
181 if (state->m_sync_mode == stereo) {
182 // Insert the autosync information into the stereo quantised codes
183 xbtEncinsertSync(&state->m_encoderData[0], &state->m_encoderData[1], &state->m_syncWordPhase);
184 } else {
185 // Insert the autosync information into the two individual mono quantised
186 // codes
187 xbtEncinsertSyncDualMono(&state->m_encoderData[0], &state->m_encoderData[1],
188 &state->m_syncWordPhase);
189 }
190 }
191
192 aptxPostEncode(&state->m_encoderData[0]);
193 aptxPostEncode(&state->m_encoderData[1]);
194
195 // Pack the (possibly adjusted) codes into a 16-bit codeword per channel
196 tmp_reg = packCodeword(&state->m_encoderData[0], state->m_sync_mode);
197 // Swap bytes to output data in big-endian as expected by bc5 code...
198 tmp_out = tmp_reg >> state->m_endian;
199 tmp_out |= tmp_reg << state->m_endian;
200
201 buffer[0] = tmp_out;
202 tmp_reg = packCodeword(&state->m_encoderData[1], state->m_sync_mode);
203 // Swap bytes to output data in big-endian as expected by bc5 code...
204 tmp_out = tmp_reg >> state->m_endian;
205 tmp_out |= tmp_reg << state->m_endian;
206
207 buffer[1] = tmp_out;
208
209 return 0;
210 }
211