2 * DSP Group TrueSpeech compatible decoder
3 * Copyright (c) 2005 Konstantin Shishkov
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "truespeech_data.h"
30 * TrueSpeech decoder context
34 int16_t vector
[8]; //< input vector: 5/5/4/4/4/3/3/3
35 int offset1
[2]; //< 8-bit value, used in one copying offset
36 int offset2
[4]; //< 7-bit value, encodes offsets for copying and for two-point filter
37 int pulseoff
[4]; //< 4-bit offset of pulse values block
38 int pulsepos
[4]; //< 27-bit variable, encodes 7 pulse positions
39 int pulseval
[4]; //< 7x2-bit pulse values
40 int flag
; //< 1-bit flag, shows how to choose filters
42 int filtbuf
[146]; // some big vector used for storing filters
43 int prevfilt
[8]; // filter from previous frame
44 int16_t tmp1
[8]; // coefficients for adding to out
45 int16_t tmp2
[8]; // coefficients for adding to out
46 int16_t tmp3
[8]; // coefficients for adding to out
47 int16_t cvector
[8]; // correlated input vector
48 int filtval
; // gain value for one function
49 int16_t newvec
[60]; // tmp vector
50 int16_t filters
[32]; // filters for every subframe
53 static av_cold
int truespeech_decode_init(AVCodecContext
* avctx
)
55 // TSContext *c = avctx->priv_data;
57 avctx
->sample_fmt
= SAMPLE_FMT_S16
;
61 static void truespeech_read_frame(TSContext
*dec
, const uint8_t *input
)
71 dec
->vector
[0] = ts_codebook
[0][(t
>> 1) & 0x1F];
72 dec
->vector
[1] = ts_codebook
[1][(t
>> 6) & 0x1F];
73 dec
->vector
[2] = ts_codebook
[2][(t
>> 11) & 0xF];
74 dec
->vector
[3] = ts_codebook
[3][(t
>> 15) & 0xF];
75 dec
->vector
[4] = ts_codebook
[4][(t
>> 19) & 0xF];
76 dec
->vector
[5] = ts_codebook
[5][(t
>> 23) & 0x7];
77 dec
->vector
[6] = ts_codebook
[6][(t
>> 26) & 0x7];
78 dec
->vector
[7] = ts_codebook
[7][(t
>> 29) & 0x7];
84 dec
->offset2
[0] = (t
>> 0) & 0x7F;
85 dec
->offset2
[1] = (t
>> 7) & 0x7F;
86 dec
->offset2
[2] = (t
>> 14) & 0x7F;
87 dec
->offset2
[3] = (t
>> 21) & 0x7F;
89 dec
->offset1
[0] = ((t
>> 28) & 0xF) << 4;
95 dec
->pulseval
[0] = (t
>> 0) & 0x3FFF;
96 dec
->pulseval
[1] = (t
>> 14) & 0x3FFF;
98 dec
->offset1
[1] = (t
>> 28) & 0x0F;
104 dec
->pulseval
[2] = (t
>> 0) & 0x3FFF;
105 dec
->pulseval
[3] = (t
>> 14) & 0x3FFF;
107 dec
->offset1
[1] |= ((t
>> 28) & 0x0F) << 4;
113 dec
->pulsepos
[0] = (t
>> 4) & 0x7FFFFFF;
115 dec
->pulseoff
[0] = (t
>> 0) & 0xF;
117 dec
->offset1
[0] |= (t
>> 31) & 1;
123 dec
->pulsepos
[1] = (t
>> 4) & 0x7FFFFFF;
125 dec
->pulseoff
[1] = (t
>> 0) & 0xF;
127 dec
->offset1
[0] |= ((t
>> 31) & 1) << 1;
133 dec
->pulsepos
[2] = (t
>> 4) & 0x7FFFFFF;
135 dec
->pulseoff
[2] = (t
>> 0) & 0xF;
137 dec
->offset1
[0] |= ((t
>> 31) & 1) << 2;
143 dec
->pulsepos
[3] = (t
>> 4) & 0x7FFFFFF;
145 dec
->pulseoff
[3] = (t
>> 0) & 0xF;
147 dec
->offset1
[0] |= ((t
>> 31) & 1) << 3;
151 static void truespeech_correlate_filter(TSContext
*dec
)
156 for(i
= 0; i
< 8; i
++){
158 memcpy(tmp
, dec
->cvector
, i
* 2);
159 for(j
= 0; j
< i
; j
++)
160 dec
->cvector
[j
] = ((tmp
[i
- j
- 1] * dec
->vector
[i
]) +
161 (dec
->cvector
[j
] << 15) + 0x4000) >> 15;
163 dec
->cvector
[i
] = (8 - dec
->vector
[i
]) >> 3;
165 for(i
= 0; i
< 8; i
++)
166 dec
->cvector
[i
] = (dec
->cvector
[i
] * ts_230
[i
]) >> 15;
168 dec
->filtval
= dec
->vector
[0];
171 static void truespeech_filters_merge(TSContext
*dec
)
176 for(i
= 0; i
< 8; i
++){
177 dec
->filters
[i
+ 0] = dec
->prevfilt
[i
];
178 dec
->filters
[i
+ 8] = dec
->prevfilt
[i
];
181 for(i
= 0; i
< 8; i
++){
182 dec
->filters
[i
+ 0]=(dec
->cvector
[i
] * 21846 + dec
->prevfilt
[i
] * 10923 + 16384) >> 15;
183 dec
->filters
[i
+ 8]=(dec
->cvector
[i
] * 10923 + dec
->prevfilt
[i
] * 21846 + 16384) >> 15;
186 for(i
= 0; i
< 8; i
++){
187 dec
->filters
[i
+ 16] = dec
->cvector
[i
];
188 dec
->filters
[i
+ 24] = dec
->cvector
[i
];
192 static void truespeech_apply_twopoint_filter(TSContext
*dec
, int quart
)
194 int16_t tmp
[146 + 60], *ptr0
, *ptr1
;
195 const int16_t *filter
;
198 t
= dec
->offset2
[quart
];
200 memset(dec
->newvec
, 0, 60 * 2);
203 for(i
= 0; i
< 146; i
++)
204 tmp
[i
] = dec
->filtbuf
[i
];
205 off
= (t
/ 25) + dec
->offset1
[quart
>> 1] + 18;
206 ptr0
= tmp
+ 145 - off
;
208 filter
= (const int16_t*)ts_240
+ (t
% 25) * 2;
209 for(i
= 0; i
< 60; i
++){
210 t
= (ptr0
[0] * filter
[0] + ptr0
[1] * filter
[1] + 0x2000) >> 14;
217 static void truespeech_place_pulses(TSContext
*dec
, int16_t *out
, int quart
)
225 memset(out
, 0, 60 * 2);
226 for(i
= 0; i
< 7; i
++) {
227 t
= dec
->pulseval
[quart
] & 3;
228 dec
->pulseval
[quart
] >>= 2;
229 tmp
[6 - i
] = ts_562
[dec
->pulseoff
[quart
] * 4 + t
];
232 coef
= dec
->pulsepos
[quart
] >> 15;
233 ptr1
= (const int16_t*)ts_140
+ 30;
235 for(i
= 0, j
= 3; (i
< 30) && (j
> 0); i
++){
245 coef
= dec
->pulsepos
[quart
] & 0x7FFF;
246 ptr1
= (const int16_t*)ts_140
;
247 for(i
= 30, j
= 4; (i
< 60) && (j
> 0); i
++){
260 static void truespeech_update_filters(TSContext
*dec
, int16_t *out
, int quart
)
264 for(i
= 0; i
< 86; i
++)
265 dec
->filtbuf
[i
] = dec
->filtbuf
[i
+ 60];
266 for(i
= 0; i
< 60; i
++){
267 dec
->filtbuf
[i
+ 86] = out
[i
] + dec
->newvec
[i
] - (dec
->newvec
[i
] >> 3);
268 out
[i
] += dec
->newvec
[i
];
272 static void truespeech_synth(TSContext
*dec
, int16_t *out
, int quart
)
276 int16_t *ptr0
, *ptr1
;
279 ptr1
= dec
->filters
+ quart
* 8;
280 for(i
= 0; i
< 60; i
++){
282 for(k
= 0; k
< 8; k
++)
283 sum
+= ptr0
[k
] * ptr1
[k
];
284 sum
= (sum
+ (out
[i
] << 12) + 0x800) >> 12;
285 out
[i
] = av_clip(sum
, -0x7FFE, 0x7FFE);
286 for(k
= 7; k
> 0; k
--)
287 ptr0
[k
] = ptr0
[k
- 1];
291 for(i
= 0; i
< 8; i
++)
292 t
[i
] = (ts_5E2
[i
] * ptr1
[i
]) >> 15;
295 for(i
= 0; i
< 60; i
++){
297 for(k
= 0; k
< 8; k
++)
298 sum
+= ptr0
[k
] * t
[k
];
299 for(k
= 7; k
> 0; k
--)
300 ptr0
[k
] = ptr0
[k
- 1];
302 out
[i
] = ((out
[i
] << 12) - sum
) >> 12;
305 for(i
= 0; i
< 8; i
++)
306 t
[i
] = (ts_5F2
[i
] * ptr1
[i
]) >> 15;
309 for(i
= 0; i
< 60; i
++){
310 int sum
= out
[i
] << 12;
311 for(k
= 0; k
< 8; k
++)
312 sum
+= ptr0
[k
] * t
[k
];
313 for(k
= 7; k
> 0; k
--)
314 ptr0
[k
] = ptr0
[k
- 1];
315 ptr0
[0] = av_clip((sum
+ 0x800) >> 12, -0x7FFE, 0x7FFE);
317 sum
= ((ptr0
[1] * (dec
->filtval
- (dec
->filtval
>> 2))) >> 4) + sum
;
318 sum
= sum
- (sum
>> 3);
319 out
[i
] = av_clip((sum
+ 0x800) >> 12, -0x7FFE, 0x7FFE);
323 static void truespeech_save_prevvec(TSContext
*c
)
327 for(i
= 0; i
< 8; i
++)
328 c
->prevfilt
[i
] = c
->cvector
[i
];
331 static int truespeech_decode_frame(AVCodecContext
*avctx
,
332 void *data
, int *data_size
,
333 const uint8_t *buf
, int buf_size
)
335 TSContext
*c
= avctx
->priv_data
;
338 short *samples
= data
;
340 int16_t out_buf
[240];
346 iterations
= FFMIN(buf_size
/ 32, *data_size
/ 480);
347 for(j
= 0; j
< iterations
; j
++) {
348 truespeech_read_frame(c
, buf
+ consumed
);
351 truespeech_correlate_filter(c
);
352 truespeech_filters_merge(c
);
354 memset(out_buf
, 0, 240 * 2);
355 for(i
= 0; i
< 4; i
++) {
356 truespeech_apply_twopoint_filter(c
, i
);
357 truespeech_place_pulses(c
, out_buf
+ i
* 60, i
);
358 truespeech_update_filters(c
, out_buf
+ i
* 60, i
);
359 truespeech_synth(c
, out_buf
+ i
* 60, i
);
362 truespeech_save_prevvec(c
);
364 /* finally output decoded frame */
365 for(i
= 0; i
< 240; i
++)
366 *samples
++ = out_buf
[i
];
370 *data_size
= consumed
* 15;
375 AVCodec truespeech_decoder
= {
380 truespeech_decode_init
,
383 truespeech_decode_frame
,
384 .long_name
= NULL_IF_CONFIG_SMALL("DSP Group TrueSpeech"),