## ffmpeg / libavcodec / qcelpdec.c @ 3f16ed15

History | View | Annotate | Download (24.3 KB)

1 | cb377ec5 | Kenan Gillet | ```
/*
``` |
---|---|---|---|

2 | ```
* QCELP decoder
``` |
||

3 | ```
* Copyright (c) 2007 Reynaldo H. Verdejo Pinochet
``` |
||

4 | ```
*
``` |
||

5 | ```
* This file is part of FFmpeg.
``` |
||

6 | ```
*
``` |
||

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.
``` |
||

11 | ```
*
``` |
||

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.
``` |
||

16 | ```
*
``` |
||

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
``` |
||

20 | ```
*/
``` |
||

21 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | |

22 | cb377ec5 | Kenan Gillet | ```
/**
``` |

23 | ```
* @file qcelpdec.c
``` |
||

24 | ```
* QCELP decoder
``` |
||

25 | ```
* @author Reynaldo H. Verdejo Pinochet
``` |
||

26 | 8e36385a | Reynaldo H. Verdejo Pinochet | ```
* @remark FFmpeg merging spearheaded by Kenan Gillet
``` |

27 | 9e00c20e | Reynaldo H. Verdejo Pinochet | ```
* @remark Development mentored by Benjamin Larson
``` |

28 | cb377ec5 | Kenan Gillet | ```
*/
``` |

29 | |||

30 | #include <stddef.h> |
||

31 | |||

32 | #include "avcodec.h" |
||

33 | dbbec0c2 | Stefano Sabatini | #include "internal.h" |

34 | cb377ec5 | Kenan Gillet | #include "bitstream.h" |

35 | |||

36 | #include "qcelpdata.h" |
||

37 | |||

38 | #include "celp_math.h" |
||

39 | #include "celp_filters.h" |
||

40 | |||

41 | ```
#undef NDEBUG
``` |
||

42 | #include <assert.h> |
||

43 | |||

44 | 061f407e | Kenan Gillet | typedef enum |

45 | { |
||

46 | I_F_Q = -1, /*!< insufficient frame quality */ |
||

47 | SILENCE, |
||

48 | RATE_OCTAVE, |
||

49 | RATE_QUARTER, |
||

50 | RATE_HALF, |
||

51 | RATE_FULL |
||

52 | } qcelp_packet_rate; |
||

53 | |||

54 | cf139541 | Reynaldo H. Verdejo Pinochet | typedef struct |

55 | { |
||

56 | 640760da | Kenan Gillet | GetBitContext gb; |

57 | qcelp_packet_rate bitrate; |
||

58 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
QCELPFrame frame; /*!< unpacked data frame */
``` |

59 | |||

60 | uint8_t erasure_count; |
||

61 | ```
uint8_t octave_count; /*!< count the consecutive RATE_OCTAVE frames */
``` |
||

62 | float prev_lspf[10]; |
||

63 | 751ccc48 | Reynaldo H. Verdejo Pinochet | float predictor_lspf[10];/*!< LSP predictor for RATE_OCTAVE and I_F_Q */ |

64 | cf139541 | Reynaldo H. Verdejo Pinochet | float pitch_synthesis_filter_mem[303]; |

65 | float pitch_pre_filter_mem[303]; |
||

66 | float rnd_fir_filter_mem[180]; |
||

67 | float formant_mem[170]; |
||

68 | ```
float last_codebook_gain;
``` |
||

69 | int prev_g1[2]; |
||

70 | ```
int prev_bitrate;
``` |
||

71 | float pitch_gain[4]; |
||

72 | ```
uint8_t pitch_lag[4];
``` |
||

73 | uint16_t first16bits; |
||

74 | 5a3e9f2c | Kenan Gillet | uint8_t warned_buf_mismatch_bitrate; |

75 | 640760da | Kenan Gillet | } QCELPContext; |

76 | |||

77 | 061f407e | Kenan Gillet | ```
/**
``` |

78 | ```
* Reconstructs LPC coefficients from the line spectral pair frequencies.
``` |
||

79 | ```
*
``` |
||

80 | ```
* TIA/EIA/IS-733 2.4.3.3.5
``` |
||

81 | ```
*/
``` |
||

82 | 73b458e3 | Kenan Gillet | void ff_qcelp_lspf2lpc(const float *lspf, float *lpc); |

83 | 061f407e | Kenan Gillet | |

84 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | static void weighted_vector_sumf(float *out, const float *in_a, |

85 | const float *in_b, float weight_coeff_a, |
||

86 | float weight_coeff_b, int length) |
||

87 | { |
||

88 | ```
int i;
``` |
||

89 | 2ae1a9b2 | Kenan Gillet | |

90 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | for(i=0; i<length; i++) |

91 | 2ae1a9b2 | Kenan Gillet | out[i] = weight_coeff_a * in_a[i] |

92 | + weight_coeff_b * in_b[i]; |
||

93 | } |
||

94 | |||

95 | cb377ec5 | Kenan Gillet | ```
/**
``` |

96 | 39ded680 | Kenan Gillet | ```
* Initialize the speech codec according to the specification.
``` |

97 | ```
*
``` |
||

98 | ```
* TIA/EIA/IS-733 2.4.9
``` |
||

99 | ```
*/
``` |
||

100 | 1b321c5c | Reynaldo H. Verdejo Pinochet | static av_cold int qcelp_decode_init(AVCodecContext *avctx) |

101 | { |
||

102 | 39ded680 | Kenan Gillet | QCELPContext *q = avctx->priv_data; |

103 | ```
int i;
``` |
||

104 | |||

105 | avctx->sample_fmt = SAMPLE_FMT_FLT; |
||

106 | |||

107 | cf139541 | Reynaldo H. Verdejo Pinochet | for(i=0; i<10; i++) |

108 | q->prev_lspf[i] = (i+1)/11.; |
||

109 | 39ded680 | Kenan Gillet | |

110 | return 0; |
||

111 | } |
||

112 | |||

113 | ```
/**
``` |
||

114 | 148c31b9 | Kenan Gillet | ```
* Decodes the 10 quantized LSP frequencies from the LSPV/LSP
``` |

115 | ```
* transmission codes of any bitrate and checks for badly received packets.
``` |
||

116 | ```
*
``` |
||

117 | ```
* @param q the context
``` |
||

118 | ```
* @param lspf line spectral pair frequencies
``` |
||

119 | ```
*
``` |
||

120 | ```
* @return 0 on success, -1 if the packet is badly received
``` |
||

121 | ```
*
``` |
||

122 | ```
* TIA/EIA/IS-733 2.4.3.2.6.2-2, 2.4.8.7.3
``` |
||

123 | ```
*/
``` |
||

124 | 1b321c5c | Reynaldo H. Verdejo Pinochet | static int decode_lspf(QCELPContext *q, float *lspf) |

125 | { |
||

126 | 148c31b9 | Kenan Gillet | ```
int i;
``` |

127 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
float tmp_lspf, smooth, erasure_coeff;
``` |

128 | const float *predictors; |
||

129 | 148c31b9 | Kenan Gillet | |

130 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate == RATE_OCTAVE || q->bitrate == I_F_Q)
``` |

131 | { |
||

132 | cf139541 | Reynaldo H. Verdejo Pinochet | predictors = (q->prev_bitrate != RATE_OCTAVE && |

133 | q->prev_bitrate != I_F_Q ? |
||

134 | q->prev_lspf : q->predictor_lspf); |
||

135 | 148c31b9 | Kenan Gillet | |

136 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate == RATE_OCTAVE)
``` |

137 | { |
||

138 | 148c31b9 | Kenan Gillet | q->octave_count++; |

139 | |||

140 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=0; i<10; i++) |

141 | { |
||

142 | 148c31b9 | Kenan Gillet | q->predictor_lspf[i] = |

143 | 640760da | Kenan Gillet | lspf[i] = (q->frame.lspv[i] ? QCELP_LSP_SPREAD_FACTOR |

144 | : -QCELP_LSP_SPREAD_FACTOR) |
||

145 | 148c31b9 | Kenan Gillet | + predictors[i] * QCELP_LSP_OCTAVE_PREDICTOR |

146 | + (i + 1) * ((1 - QCELP_LSP_OCTAVE_PREDICTOR)/11); |
||

147 | } |
||

148 | smooth = (q->octave_count < 10 ? .875 : 0.1); |
||

149 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

150 | { |
||

151 | cf139541 | Reynaldo H. Verdejo Pinochet | erasure_coeff = QCELP_LSP_OCTAVE_PREDICTOR; |

152 | 148c31b9 | Kenan Gillet | |

153 | assert(q->bitrate == I_F_Q); |
||

154 | |||

155 | 1b321c5c | Reynaldo H. Verdejo Pinochet | if(q->erasure_count > 1) |

156 | 148c31b9 | Kenan Gillet | erasure_coeff *= (q->erasure_count < 4 ? 0.9 : 0.7); |

157 | |||

158 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=0; i<10; i++) |

159 | { |
||

160 | 148c31b9 | Kenan Gillet | q->predictor_lspf[i] = |

161 | lspf[i] = (i + 1) * ( 1 - erasure_coeff)/11 |
||

162 | + erasure_coeff * predictors[i]; |
||

163 | } |
||

164 | smooth = 0.125; |
||

165 | } |
||

166 | |||

167 | ```
// Check the stability of the LSP frequencies.
``` |
||

168 | lspf[0] = FFMAX(lspf[0], QCELP_LSP_SPREAD_FACTOR); |
||

169 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=1; i<10; i++) |

170 | 148c31b9 | Kenan Gillet | ```
lspf[i] = FFMAX(lspf[i], (lspf[i-1] + QCELP_LSP_SPREAD_FACTOR));
``` |

171 | |||

172 | lspf[9] = FFMIN(lspf[9], (1.0 - QCELP_LSP_SPREAD_FACTOR)); |
||

173 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=9; i>0; i--) |

174 | 148c31b9 | Kenan Gillet | lspf[i-1] = FFMIN(lspf[i-1], (lspf[i] - QCELP_LSP_SPREAD_FACTOR)); |

175 | |||

176 | ```
// Low-pass filter the LSP frequencies.
``` |
||

177 | 1b321c5c | Reynaldo H. Verdejo Pinochet | weighted_vector_sumf(lspf, lspf, q->prev_lspf, smooth, 1.0-smooth, 10); |

178 | ```
}else
``` |
||

179 | { |
||

180 | 148c31b9 | Kenan Gillet | ```
q->octave_count = 0;
``` |

181 | |||

182 | ```
tmp_lspf = 0.;
``` |
||

183 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=0; i<5 ; i++) |

184 | { |
||

185 | 640760da | Kenan Gillet | lspf[2*i+0] = tmp_lspf += qcelp_lspvq[i][q->frame.lspv[i]][0] * 0.0001; |

186 | lspf[2*i+1] = tmp_lspf += qcelp_lspvq[i][q->frame.lspv[i]][1] * 0.0001; |
||

187 | 148c31b9 | Kenan Gillet | } |

188 | |||

189 | ```
// Check for badly received packets.
``` |
||

190 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate == RATE_QUARTER)
``` |

191 | { |
||

192 | if(lspf[9] <= .70 || lspf[9] >= .97) |
||

193 | 148c31b9 | Kenan Gillet | return -1; |

194 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=3; i<10; i++) |

195 | if(fabs(lspf[i] - lspf[i-2]) < .08) |
||

196 | 148c31b9 | Kenan Gillet | return -1; |

197 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

198 | { |
||

199 | if(lspf[9] <= .66 || lspf[9] >= .985) |
||

200 | 148c31b9 | Kenan Gillet | return -1; |

201 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=4; i<10; i++) |

202 | 148c31b9 | Kenan Gillet | if (fabs(lspf[i] - lspf[i-4]) < .0931) |

203 | return -1; |
||

204 | } |
||

205 | } |
||

206 | return 0; |
||

207 | } |
||

208 | |||

209 | ```
/**
``` |
||

210 | 640760da | Kenan Gillet | ```
* Converts codebook transmission codes to GAIN and INDEX.
``` |

211 | ```
*
``` |
||

212 | ```
* @param q the context
``` |
||

213 | ```
* @param gain array holding the decoded gain
``` |
||

214 | ```
*
``` |
||

215 | ```
* TIA/EIA/IS-733 2.4.6.2
``` |
||

216 | ```
*/
``` |
||

217 | static void decode_gain_and_index(QCELPContext *q, |
||

218 | ```
float *gain) {
``` |
||

219 | int i, subframes_count, g1[16]; |
||

220 | ```
float slope;
``` |
||

221 | |||

222 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate >= RATE_QUARTER)
``` |

223 | { |
||

224 | ```
switch(q->bitrate)
``` |
||

225 | { |
||

226 | 640760da | Kenan Gillet | case RATE_FULL: subframes_count = 16; break; |

227 | case RATE_HALF: subframes_count = 4; break; |
||

228 | default: subframes_count = 5; |
||

229 | } |
||

230 | cf139541 | Reynaldo H. Verdejo Pinochet | for(i=0; i<subframes_count; i++) |

231 | { |
||

232 | 640760da | Kenan Gillet | ```
g1[i] = 4 * q->frame.cbgain[i];
``` |

233 | cf139541 | Reynaldo H. Verdejo Pinochet | if(q->bitrate == RATE_FULL && !((i+1) & 3)) |

234 | { |
||

235 | 640760da | Kenan Gillet | g1[i] += av_clip((g1[i-1] + g1[i-2] + g1[i-3]) / 3 - 6, 0, 32); |

236 | } |
||

237 | |||

238 | gain[i] = qcelp_g12ga[g1[i]]; |
||

239 | |||

240 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->frame.cbsign[i])
``` |

241 | { |
||

242 | 640760da | Kenan Gillet | gain[i] = -gain[i]; |

243 | q->frame.cindex[i] = (q->frame.cindex[i]-89) & 127; |
||

244 | } |
||

245 | } |
||

246 | |||

247 | q->prev_g1[0] = g1[i-2]; |
||

248 | q->prev_g1[1] = g1[i-1]; |
||

249 | ```
q->last_codebook_gain = qcelp_g12ga[g1[i-1]];
``` |
||

250 | |||

251 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate == RATE_QUARTER)
``` |

252 | { |
||

253 | 640760da | Kenan Gillet | ```
// Provide smoothing of the unvoiced excitation energy.
``` |

254 | gain[7] = gain[4]; |
||

255 | gain[6] = 0.4*gain[3] + 0.6*gain[4]; |
||

256 | gain[5] = gain[3]; |
||

257 | gain[4] = 0.8*gain[2] + 0.2*gain[3]; |
||

258 | gain[3] = 0.2*gain[1] + 0.8*gain[2]; |
||

259 | gain[2] = gain[1]; |
||

260 | gain[1] = 0.6*gain[0] + 0.4*gain[1]; |
||

261 | } |
||

262 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

263 | { |
||

264 | ```
if(q->bitrate == RATE_OCTAVE)
``` |
||

265 | { |
||

266 | 640760da | Kenan Gillet | g1[0] = 2 * q->frame.cbgain[0] |

267 | + av_clip((q->prev_g1[0] + q->prev_g1[1]) / 2 - 5, 0, 54); |
||

268 | ```
subframes_count = 8;
``` |
||

269 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

270 | { |
||

271 | 640760da | Kenan Gillet | assert(q->bitrate == I_F_Q); |

272 | |||

273 | g1[0] = q->prev_g1[1]; |
||

274 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
switch(q->erasure_count)
``` |

275 | { |
||

276 | case 1 : break; |
||

277 | case 2 : g1[0] -= 1; break; |
||

278 | case 3 : g1[0] -= 2; break; |
||

279 | default: g1[0] -= 6; |
||

280 | 640760da | Kenan Gillet | } |

281 | cf139541 | Reynaldo H. Verdejo Pinochet | if(g1[0] < 0) |

282 | 640760da | Kenan Gillet | g1[0] = 0; |

283 | ```
subframes_count = 4;
``` |
||

284 | } |
||

285 | ```
// This interpolation is done to produce smoother background noise.
``` |
||

286 | slope = 0.5*(qcelp_g12ga[g1[0]] - q->last_codebook_gain) / subframes_count; |
||

287 | cf139541 | Reynaldo H. Verdejo Pinochet | for(i=1; i<=subframes_count; i++) |

288 | 640760da | Kenan Gillet | ```
gain[i-1] = q->last_codebook_gain + slope * i;
``` |

289 | |||

290 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
q->last_codebook_gain = gain[i-2];
``` |

291 | 640760da | Kenan Gillet | q->prev_g1[0] = q->prev_g1[1]; |

292 | q->prev_g1[1] = g1[0]; |
||

293 | } |
||

294 | } |
||

295 | |||

296 | ```
/**
``` |
||

297 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
* If the received packet is Rate 1/4 a further sanity check is made of the
``` |

298 | ```
* codebook gain.
``` |
||

299 | 148c31b9 | Kenan Gillet | ```
*
``` |

300 | ```
* @param cbgain the unpacked cbgain array
``` |
||

301 | ```
* @return -1 if the sanity check fails, 0 otherwise
``` |
||

302 | ```
*
``` |
||

303 | ```
* TIA/EIA/IS-733 2.4.8.7.3
``` |
||

304 | ```
*/
``` |
||

305 | 1b321c5c | Reynaldo H. Verdejo Pinochet | static int codebook_sanity_check_for_rate_quarter(const uint8_t *cbgain) |

306 | { |
||

307 | cf139541 | Reynaldo H. Verdejo Pinochet | int i, diff, prev_diff=0; |

308 | 148c31b9 | Kenan Gillet | |

309 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=1; i<5; i++) |

310 | { |
||

311 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
diff = cbgain[i] - cbgain[i-1];
``` |

312 | 1b321c5c | Reynaldo H. Verdejo Pinochet | if(FFABS(diff) > 10) |

313 | return -1; |
||

314 | else if(FFABS(diff - prev_diff) > 12) |
||

315 | return -1; |
||

316 | prev_diff = diff; |
||

317 | 8372e3d2 | Reynaldo H. Verdejo Pinochet | } |

318 | return 0; |
||

319 | 148c31b9 | Kenan Gillet | } |

320 | |||

321 | ```
/**
``` |
||

322 | 39ded680 | Kenan Gillet | ```
* Computes the scaled codebook vector Cdn From INDEX and GAIN
``` |

323 | ```
* for all rates.
``` |
||

324 | ```
*
``` |
||

325 | ```
* The specification lacks some information here.
``` |
||

326 | ```
*
``` |
||

327 | ```
* TIA/EIA/IS-733 has an omission on the codebook index determination
``` |
||

328 | ```
* formula for RATE_FULL and RATE_HALF frames at section 2.4.8.1.1. It says
``` |
||

329 | ```
* you have to subtract the decoded index parameter from the given scaled
``` |
||

330 | ```
* codebook vector index 'n' to get the desired circular codebook index, but
``` |
||

331 | ```
* it does not mention that you have to clamp 'n' to [0-9] in order to get
``` |
||

332 | ```
* RI-compliant results.
``` |
||

333 | ```
*
``` |
||

334 | ```
* The reason for this mistake seems to be the fact they forgot to mention you
``` |
||

335 | ```
* have to do these calculations per codebook subframe and adjust given
``` |
||

336 | ```
* equation values accordingly.
``` |
||

337 | ```
*
``` |
||

338 | ```
* @param q the context
``` |
||

339 | ```
* @param gain array holding the 4 pitch subframe gain values
``` |
||

340 | ```
* @param cdn_vector array for the generated scaled codebook vector
``` |
||

341 | ```
*/
``` |
||

342 | b12c7627 | Reynaldo H. Verdejo Pinochet | static void compute_svector(QCELPContext *q, const float *gain, |

343 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
float *cdn_vector)
``` |

344 | { |
||

345 | 39ded680 | Kenan Gillet | ```
int i, j, k;
``` |

346 | uint16_t cbseed, cindex; |
||

347 | ```
float *rnd, tmp_gain, fir_filter_value;
``` |
||

348 | |||

349 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
switch(q->bitrate)
``` |

350 | { |
||

351 | ```
case RATE_FULL:
``` |
||

352 | for(i=0; i<16; i++) |
||

353 | { |
||

354 | tmp_gain = gain[i] * QCELP_RATE_FULL_CODEBOOK_RATIO; |
||

355 | 640760da | Kenan Gillet | cindex = -q->frame.cindex[i]; |

356 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(j=0; j<10; j++) |

357 | ```
*cdn_vector++ = tmp_gain * qcelp_rate_full_codebook[cindex++ & 127];
``` |
||

358 | } |
||

359 | 39ded680 | Kenan Gillet | ```
break;
``` |

360 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
case RATE_HALF:
``` |

361 | for(i=0; i<4; i++) |
||

362 | { |
||

363 | tmp_gain = gain[i] * QCELP_RATE_HALF_CODEBOOK_RATIO; |
||

364 | 640760da | Kenan Gillet | cindex = -q->frame.cindex[i]; |

365 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for (j = 0; j < 40; j++) |

366 | 39ded680 | Kenan Gillet | ```
*cdn_vector++ = tmp_gain * qcelp_rate_half_codebook[cindex++ & 127];
``` |

367 | 1b321c5c | Reynaldo H. Verdejo Pinochet | } |

368 | 39ded680 | Kenan Gillet | ```
break;
``` |

369 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
case RATE_QUARTER:
``` |

370 | 640760da | Kenan Gillet | cbseed = (0x0003 & q->frame.lspv[4])<<14 | |

371 | (0x003F & q->frame.lspv[3])<< 8 | |
||

372 | (0x0060 & q->frame.lspv[2])<< 1 | |
||

373 | (0x0007 & q->frame.lspv[1])<< 3 | |
||

374 | (0x0038 & q->frame.lspv[0])>> 3 ; |
||

375 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
rnd = q->rnd_fir_filter_mem + 20;
``` |

376 | for(i=0; i<8; i++) |
||

377 | { |
||

378 | tmp_gain = gain[i] * (QCELP_SQRT1887 / 32768.0); |
||

379 | for(k=0; k<20; k++) |
||

380 | { |
||

381 | cbseed = 521 * cbseed + 259; |
||

382 | *rnd = (int16_t)cbseed; |
||

383 | |||

384 | ```
// FIR filter
``` |
||

385 | fir_filter_value = 0.0; |
||

386 | for(j=0; j<10; j++) |
||

387 | fir_filter_value += qcelp_rnd_fir_coefs[j ] |
||

388 | ```
* (rnd[-j ] + rnd[-20+j]);
``` |
||

389 | |||

390 | fir_filter_value += qcelp_rnd_fir_coefs[10] * rnd[-10]; |
||

391 | *cdn_vector++ = tmp_gain * fir_filter_value; |
||

392 | rnd++; |
||

393 | } |
||

394 | 39ded680 | Kenan Gillet | } |

395 | 1b321c5c | Reynaldo H. Verdejo Pinochet | memcpy(q->rnd_fir_filter_mem, q->rnd_fir_filter_mem + 160, 20 * sizeof(float)); |

396 | 39ded680 | Kenan Gillet | ```
break;
``` |

397 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
case RATE_OCTAVE:
``` |

398 | cbseed = q->first16bits; |
||

399 | for(i=0; i<8; i++) |
||

400 | { |
||

401 | tmp_gain = gain[i] * (QCELP_SQRT1887 / 32768.0); |
||

402 | for(j=0; j<20; j++) |
||

403 | { |
||

404 | cbseed = 521 * cbseed + 259; |
||

405 | *cdn_vector++ = tmp_gain * (int16_t)cbseed; |
||

406 | } |
||

407 | 39ded680 | Kenan Gillet | } |

408 | ```
break;
``` |
||

409 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
case I_F_Q:
``` |

410 | cbseed = -44; // random codebook index |
||

411 | for(i=0; i<4; i++) |
||

412 | { |
||

413 | tmp_gain = gain[i] * QCELP_RATE_FULL_CODEBOOK_RATIO; |
||

414 | for(j=0; j<40; j++) |
||

415 | ```
*cdn_vector++ = tmp_gain * qcelp_rate_full_codebook[cbseed++ & 127];
``` |
||

416 | } |
||

417 | 39ded680 | Kenan Gillet | ```
break;
``` |

418 | } |
||

419 | } |
||

420 | |||

421 | ```
/**
``` |
||

422 | ```
* Apply generic gain control.
``` |
||

423 | ```
*
``` |
||

424 | ```
* @param v_out output vector
``` |
||

425 | ```
* @param v_in gain-controlled vector
``` |
||

426 | ```
* @param v_ref vector to control gain of
``` |
||

427 | ```
*
``` |
||

428 | ```
* FIXME: If v_ref is a zero vector, it energy is zero
``` |
||

429 | ```
* and the behavior of the gain control is
``` |
||

430 | ```
* undefined in the specs.
``` |
||

431 | ```
*
``` |
||

432 | ```
* TIA/EIA/IS-733 2.4.8.3-2/3/4/5, 2.4.8.6
``` |
||

433 | ```
*/
``` |
||

434 | 1b321c5c | Reynaldo H. Verdejo Pinochet | static void apply_gain_ctrl(float *v_out, const float *v_ref, |

435 | const float *v_in) |
||

436 | { |
||

437 | 39ded680 | Kenan Gillet | ```
int i, j, len;
``` |

438 | ```
float scalefactor;
``` |
||

439 | |||

440 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(i=0, j=0; i<4; i++) |

441 | { |
||

442 | 39ded680 | Kenan Gillet | ```
scalefactor = ff_dot_productf(v_in + j, v_in + j, 40);
``` |

443 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
if(scalefactor)
``` |

444 | ```
scalefactor = sqrt(ff_dot_productf(v_ref + j, v_ref + j, 40)
``` |
||

445 | / scalefactor); |
||

446 | 39ded680 | Kenan Gillet | ```
else
``` |

447 | dbbec0c2 | Stefano Sabatini | ff_log_missing_feature(NULL, "Zero energy for gain control", 1); |

448 | 1b321c5c | Reynaldo H. Verdejo Pinochet | for(len=j+40; j<len; j++) |

449 | 39ded680 | Kenan Gillet | v_out[j] = scalefactor * v_in[j]; |

450 | } |
||

451 | } |
||

452 | |||

453 | ```
/**
``` |
||

454 | cb377ec5 | Kenan Gillet | ```
* Apply filter in pitch-subframe steps.
``` |

455 | ```
*
``` |
||

456 | ```
* @param memory buffer for the previous state of the filter
``` |
||

457 | ```
* - must be able to contain 303 elements
``` |
||

458 | ```
* - the 143 first elements are from the previous state
``` |
||

459 | ```
* - the next 160 are for output
``` |
||

460 | ```
* @param v_in input filter vector
``` |
||

461 | ```
* @param gain per-subframe gain array, each element is between 0.0 and 2.0
``` |
||

462 | ```
* @param lag per-subframe lag array, each element is
``` |
||

463 | ```
* - between 16 and 143 if its corresponding pfrac is 0,
``` |
||

464 | ```
* - between 16 and 139 otherwise
``` |
||

465 | 1b321c5c | Reynaldo H. Verdejo Pinochet | ```
* @param pfrac per-subframe boolean array, 1 if the lag is fractional, 0
``` |

466 | ```
* otherwise
``` |
||

467 | cb377ec5 | Kenan Gillet | ```
*
``` |

468 | ```
* @return filter output vector
``` |
||

469 | ```
*/
``` |
||

470 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | static const float *do_pitchfilter(float memory[303], const float v_in[160], |

471 | const float gain[4], const uint8_t *lag, |
||

472 | const uint8_t pfrac[4]) |
||

473 | { |
||

474 | cb377ec5 | Kenan Gillet | ```
int i, j;
``` |

475 | ```
float *v_lag, *v_out;
``` |
||

476 | const float *v_len; |
||

477 | |||

478 | v_out = memory + 143; // Output vector starts at memory[143]. |
||

479 | |||

480 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | for(i=0; i<4; i++) |

481 | { |
||

482 | ```
if(gain[i])
``` |
||

483 | { |
||

484 | cb377ec5 | Kenan Gillet | v_lag = memory + 143 + 40 * i - lag[i]; |

485 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | for(v_len=v_in+40; v_in<v_len; v_in++) |

486 | { |
||

487 | if(pfrac[i]) // If it is a fractional lag... |
||

488 | { |
||

489 | for(j=0, *v_out=0.; j<4; j++) |
||

490 | cb377ec5 | Kenan Gillet | *v_out += qcelp_hammsinc_table[j] * (v_lag[j-4] + v_lag[3-j]); |

491 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

492 | cb377ec5 | Kenan Gillet | *v_out = *v_lag; |

493 | |||

494 | *v_out = *v_in + gain[i] * *v_out; |
||

495 | |||

496 | v_lag++; |
||

497 | v_out++; |
||

498 | } |
||

499 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

500 | { |
||

501 | cb377ec5 | Kenan Gillet | memcpy(v_out, v_in, 40 * sizeof(float)); |

502 | ```
v_in += 40;
``` |
||

503 | ```
v_out += 40;
``` |
||

504 | } |
||

505 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | } |

506 | cb377ec5 | Kenan Gillet | |

507 | memmove(memory, memory + 160, 143 * sizeof(float)); |
||

508 | return memory + 143; |
||

509 | } |
||

510 | |||

511 | 200de8c6 | Kenan Gillet | ```
/**
``` |

512 | 73b458e3 | Kenan Gillet | ```
* Apply pitch synthesis filter and pitch prefilter to the scaled codebook vector.
``` |

513 | ```
* TIA/EIA/IS-733 2.4.5.2
``` |
||

514 | ```
*
``` |
||

515 | ```
* @param q the context
``` |
||

516 | ```
* @param cdn_vector the scaled codebook vector
``` |
||

517 | ```
*/
``` |
||

518 | cf139541 | Reynaldo H. Verdejo Pinochet | static void apply_pitch_filters(QCELPContext *q, float *cdn_vector) |

519 | { |
||

520 | 73b458e3 | Kenan Gillet | ```
int i;
``` |

521 | const float *v_synthesis_filtered, *v_pre_filtered; |
||

522 | |||

523 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate >= RATE_HALF ||
``` |

524 | (q->bitrate == I_F_Q && (q->prev_bitrate >= RATE_HALF))) |
||

525 | { |
||

526 | 73b458e3 | Kenan Gillet | |

527 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate >= RATE_HALF)
``` |

528 | { |
||

529 | 73b458e3 | Kenan Gillet | |

530 | ```
// Compute gain & lag for the whole frame.
``` |
||

531 | cf139541 | Reynaldo H. Verdejo Pinochet | for(i=0; i<4; i++) |

532 | { |
||

533 | 73b458e3 | Kenan Gillet | q->pitch_gain[i] = q->frame.plag[i] ? (q->frame.pgain[i] + 1) * 0.25 : 0.0; |

534 | |||

535 | ```
q->pitch_lag[i] = q->frame.plag[i] + 16;
``` |
||

536 | } |
||

537 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

538 | { |
||

539 | 3f16ed15 | Reynaldo H. Verdejo Pinochet | ```
float max_pitch_gain;
``` |

540 | |||

541 | if (q->erasure_count < 3) |
||

542 | max_pitch_gain = 0.9 - 0.3 * (q->erasure_count - 1); |
||

543 | ```
else
``` |
||

544 | max_pitch_gain = 0.0; |
||

545 | cf139541 | Reynaldo H. Verdejo Pinochet | for(i=0; i<4; i++) |

546 | 73b458e3 | Kenan Gillet | q->pitch_gain[i] = FFMIN(q->pitch_gain[i], max_pitch_gain); |

547 | |||

548 | memset(q->frame.pfrac, 0, sizeof(q->frame.pfrac)); |
||

549 | } |
||

550 | |||

551 | ```
// pitch synthesis filter
``` |
||

552 | cf139541 | Reynaldo H. Verdejo Pinochet | v_synthesis_filtered = do_pitchfilter(q->pitch_synthesis_filter_mem, |

553 | cdn_vector, q->pitch_gain, |
||

554 | q->pitch_lag, q->frame.pfrac); |
||

555 | 73b458e3 | Kenan Gillet | |

556 | ```
// pitch prefilter update
``` |
||

557 | cf139541 | Reynaldo H. Verdejo Pinochet | for(i=0; i<4; i++) |

558 | 73b458e3 | Kenan Gillet | q->pitch_gain[i] = 0.5 * FFMIN(q->pitch_gain[i], 1.0); |

559 | |||

560 | cf139541 | Reynaldo H. Verdejo Pinochet | v_pre_filtered = do_pitchfilter(q->pitch_pre_filter_mem, |

561 | v_synthesis_filtered, |
||

562 | q->pitch_gain, q->pitch_lag, |
||

563 | q->frame.pfrac); |
||

564 | 73b458e3 | Kenan Gillet | |

565 | apply_gain_ctrl(cdn_vector, v_synthesis_filtered, v_pre_filtered); |
||

566 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

567 | { |
||

568 | ```
memcpy(q->pitch_synthesis_filter_mem, cdn_vector + 17,
``` |
||

569 | 143 * sizeof(float)); |
||

570 | memcpy(q->pitch_pre_filter_mem, cdn_vector + 17, 143 * sizeof(float)); |
||

571 | 73b458e3 | Kenan Gillet | memset(q->pitch_gain, 0, sizeof(q->pitch_gain)); |

572 | memset(q->pitch_lag, 0, sizeof(q->pitch_lag)); |
||

573 | } |
||

574 | } |
||

575 | |||

576 | ```
/**
``` |
||

577 | 200de8c6 | Kenan Gillet | ```
* Interpolates LSP frequencies and computes LPC coefficients
``` |

578 | 148c31b9 | Kenan Gillet | ```
* for a given bitrate & pitch subframe.
``` |

579 | 200de8c6 | Kenan Gillet | ```
*
``` |

580 | ```
* TIA/EIA/IS-733 2.4.3.3.4
``` |
||

581 | ```
*
``` |
||

582 | ```
* @param q the context
``` |
||

583 | ```
* @param curr_lspf LSP frequencies vector of the current frame
``` |
||

584 | ```
* @param lpc float vector for the resulting LPC
``` |
||

585 | ```
* @param subframe_num frame number in decoded stream
``` |
||

586 | ```
*/
``` |
||

587 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | void interpolate_lpc(QCELPContext *q, const float *curr_lspf, float *lpc, |

588 | const int subframe_num) |
||

589 | { |
||

590 | 200de8c6 | Kenan Gillet | float interpolated_lspf[10]; |

591 | ```
float weight;
``` |
||

592 | |||

593 | 148c31b9 | Kenan Gillet | ```
if(q->bitrate >= RATE_QUARTER)
``` |

594 | 200de8c6 | Kenan Gillet | weight = 0.25 * (subframe_num + 1); |

595 | 148c31b9 | Kenan Gillet | else if(q->bitrate == RATE_OCTAVE && !subframe_num) |

596 | 200de8c6 | Kenan Gillet | weight = 0.625; |

597 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | ```
else
``` |

598 | 200de8c6 | Kenan Gillet | weight = 1.0; |

599 | |||

600 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | if(weight != 1.0) |

601 | { |
||

602 | weighted_vector_sumf(interpolated_lspf, curr_lspf, q->prev_lspf, |
||

603 | weight, 1.0 - weight, 10); |
||

604 | 73b458e3 | Kenan Gillet | ff_qcelp_lspf2lpc(interpolated_lspf, lpc); |

605 | cf139541 | Reynaldo H. Verdejo Pinochet | }else if(q->bitrate >= RATE_QUARTER || |

606 | (q->bitrate == I_F_Q && !subframe_num)) |
||

607 | 73b458e3 | Kenan Gillet | ff_qcelp_lspf2lpc(curr_lspf, lpc); |

608 | 200de8c6 | Kenan Gillet | } |

609 | |||

610 | 6e74619e | Vitor Sessak | static qcelp_packet_rate buf_size2bitrate(const int buf_size) |

611 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | { |

612 | ```
switch(buf_size)
``` |
||

613 | { |
||

614 | cf139541 | Reynaldo H. Verdejo Pinochet | case 35: return RATE_FULL; |

615 | case 17: return RATE_HALF; |
||

616 | case 8: return RATE_QUARTER; |
||

617 | case 4: return RATE_OCTAVE; |
||

618 | case 1: return SILENCE; |
||

619 | 2ae1a9b2 | Kenan Gillet | } |

620 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | |

621 | 6e74619e | Vitor Sessak | ```
return I_F_Q;
``` |

622 | 2ae1a9b2 | Kenan Gillet | } |

623 | |||

624 | 061f407e | Kenan Gillet | ```
/**
``` |

625 | ```
* Determine the bitrate from the frame size and/or the first byte of the frame.
``` |
||

626 | ```
*
``` |
||

627 | ```
* @param avctx the AV codec context
``` |
||

628 | ```
* @param buf_size length of the buffer
``` |
||

629 | ```
* @param buf the bufffer
``` |
||

630 | ```
*
``` |
||

631 | ```
* @return the bitrate on success,
``` |
||

632 | ```
* I_F_Q if the bitrate cannot be satisfactorily determined
``` |
||

633 | ```
*
``` |
||

634 | ```
* TIA/EIA/IS-733 2.4.8.7.1
``` |
||

635 | ```
*/
``` |
||

636 | cf139541 | Reynaldo H. Verdejo Pinochet | static int determine_bitrate(AVCodecContext *avctx, const int buf_size, |

637 | 87a91736 | Reynaldo H. Verdejo Pinochet | ```
const uint8_t **buf)
``` |

638 | cf139541 | Reynaldo H. Verdejo Pinochet | { |

639 | 061f407e | Kenan Gillet | qcelp_packet_rate bitrate; |

640 | |||

641 | cf139541 | Reynaldo H. Verdejo Pinochet | if((bitrate = buf_size2bitrate(buf_size)) >= 0) |

642 | { |
||

643 | ```
if(bitrate > **buf)
``` |
||

644 | { |
||

645 | 5a3e9f2c | Kenan Gillet | QCELPContext *q = avctx->priv_data; |

646 | ```
if (!q->warned_buf_mismatch_bitrate)
``` |
||

647 | { |
||

648 | cf139541 | Reynaldo H. Verdejo Pinochet | av_log(avctx, AV_LOG_WARNING, |

649 | ```
"Claimed bitrate and buffer size mismatch.\n");
``` |
||

650 | 5a3e9f2c | Kenan Gillet | ```
q->warned_buf_mismatch_bitrate = 1;
``` |

651 | } |
||

652 | 061f407e | Kenan Gillet | bitrate = **buf; |

653 | cf139541 | Reynaldo H. Verdejo Pinochet | }else if(bitrate < **buf) |

654 | { |
||

655 | av_log(avctx, AV_LOG_ERROR, |
||

656 | ```
"Buffer is too small for the claimed bitrate.\n");
``` |
||

657 | 061f407e | Kenan Gillet | ```
return I_F_Q;
``` |

658 | } |
||

659 | (*buf)++; |
||

660 | cf139541 | Reynaldo H. Verdejo Pinochet | }else if((bitrate = buf_size2bitrate(buf_size + 1)) >= 0) |

661 | { |
||

662 | 061f407e | Kenan Gillet | av_log(avctx, AV_LOG_WARNING, |

663 | ```
"Bitrate byte is missing, guessing the bitrate from packet size.\n");
``` |
||

664 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

665 | 061f407e | Kenan Gillet | ```
return I_F_Q;
``` |

666 | |||

667 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(bitrate == SILENCE)
``` |

668 | { |
||

669 | 061f407e | Kenan Gillet | ```
// FIXME: the decoder should not handle SILENCE frames as I_F_Q frames
``` |

670 | dbbec0c2 | Stefano Sabatini | ff_log_missing_feature(avctx, "Blank frame", 1); |

671 | 061f407e | Kenan Gillet | bitrate = I_F_Q; |

672 | } |
||

673 | ```
return bitrate;
``` |
||

674 | } |
||

675 | |||

676 | cb377ec5 | Kenan Gillet | static void warn_insufficient_frame_quality(AVCodecContext *avctx, |

677 | 1c3ae1ab | Reynaldo H. Verdejo Pinochet | const char *message) |

678 | { |
||

679 | ```
av_log(avctx, AV_LOG_WARNING, "Frame #%d, IFQ: %s\n", avctx->frame_number,
``` |
||

680 | message); |
||

681 | cb377ec5 | Kenan Gillet | } |

682 | 200de8c6 | Kenan Gillet | |

683 | cf139541 | Reynaldo H. Verdejo Pinochet | static int qcelp_decode_frame(AVCodecContext *avctx, void *data, int *data_size, |

684 | 87a91736 | Reynaldo H. Verdejo Pinochet | const uint8_t *buf, int buf_size) |

685 | cf139541 | Reynaldo H. Verdejo Pinochet | { |

686 | QCELPContext *q = avctx->priv_data; |
||

687 | ```
float *outbuffer = data;
``` |
||

688 | ```
int i;
``` |
||

689 | float quantized_lspf[10], lpc[10]; |
||

690 | float gain[16]; |
||

691 | ```
float *formant_mem;
``` |
||

692 | |||

693 | ```
if((q->bitrate = determine_bitrate(avctx, buf_size, &buf)) == I_F_Q)
``` |
||

694 | { |
||

695 | 640760da | Kenan Gillet | ```
warn_insufficient_frame_quality(avctx, "bitrate cannot be determined.");
``` |

696 | ```
goto erasure;
``` |
||

697 | } |
||

698 | |||

699 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate == RATE_OCTAVE &&
``` |

700 | ```
(q->first16bits = AV_RB16(buf)) == 0xFFFF)
``` |
||

701 | { |
||

702 | 640760da | Kenan Gillet | ```
warn_insufficient_frame_quality(avctx, "Bitrate is 1/8 and first 16 bits are on.");
``` |

703 | ```
goto erasure;
``` |
||

704 | } |
||

705 | |||

706 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate > SILENCE)
``` |

707 | { |
||

708 | 640760da | Kenan Gillet | ```
const QCELPBitmap *bitmaps = qcelp_unpacking_bitmaps_per_rate[q->bitrate];
``` |

709 | ```
const QCELPBitmap *bitmaps_end = qcelp_unpacking_bitmaps_per_rate[q->bitrate]
``` |
||

710 | + qcelp_unpacking_bitmaps_lengths[q->bitrate]; |
||

711 | uint8_t *unpacked_data = (uint8_t *)&q->frame; |
||

712 | |||

713 | ```
init_get_bits(&q->gb, buf, 8*buf_size);
``` |
||

714 | |||

715 | memset(&q->frame, 0, sizeof(QCELPFrame)); |
||

716 | |||

717 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
for(; bitmaps < bitmaps_end; bitmaps++)
``` |

718 | 640760da | Kenan Gillet | unpacked_data[bitmaps->index] |= get_bits(&q->gb, bitmaps->bitlen) << bitmaps->bitpos; |

719 | |||

720 | ```
// Check for erasures/blanks on rates 1, 1/4 and 1/8.
``` |
||

721 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->frame.reserved)
``` |

722 | { |
||

723 | 640760da | Kenan Gillet | ```
warn_insufficient_frame_quality(avctx, "Wrong data in reserved frame area.");
``` |

724 | ```
goto erasure;
``` |
||

725 | } |
||

726 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate == RATE_QUARTER &&
``` |

727 | codebook_sanity_check_for_rate_quarter(q->frame.cbgain)) |
||

728 | { |
||

729 | 640760da | Kenan Gillet | ```
warn_insufficient_frame_quality(avctx, "Codebook gain sanity check failed.");
``` |

730 | ```
goto erasure;
``` |
||

731 | } |
||

732 | |||

733 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate >= RATE_HALF)
``` |

734 | { |
||

735 | for(i=0; i<4; i++) |
||

736 | { |
||

737 | if(q->frame.pfrac[i] && q->frame.plag[i] >= 124) |
||

738 | { |
||

739 | 640760da | Kenan Gillet | ```
warn_insufficient_frame_quality(avctx, "Cannot initialize pitch filter.");
``` |

740 | ```
goto erasure;
``` |
||

741 | } |
||

742 | } |
||

743 | } |
||

744 | } |
||

745 | |||

746 | decode_gain_and_index(q, gain); |
||

747 | compute_svector(q, gain, outbuffer); |
||

748 | |||

749 | cf139541 | Reynaldo H. Verdejo Pinochet | if(decode_lspf(q, quantized_lspf) < 0) |

750 | { |
||

751 | 640760da | Kenan Gillet | ```
warn_insufficient_frame_quality(avctx, "Badly received packets in frame.");
``` |

752 | ```
goto erasure;
``` |
||

753 | } |
||

754 | |||

755 | |||

756 | apply_pitch_filters(q, outbuffer); |
||

757 | |||

758 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
if(q->bitrate == I_F_Q)
``` |

759 | { |
||

760 | 640760da | Kenan Gillet | ```
erasure:
``` |

761 | q->bitrate = I_F_Q; |
||

762 | q->erasure_count++; |
||

763 | decode_gain_and_index(q, gain); |
||

764 | compute_svector(q, gain, outbuffer); |
||

765 | decode_lspf(q, quantized_lspf); |
||

766 | apply_pitch_filters(q, outbuffer); |
||

767 | cf139541 | Reynaldo H. Verdejo Pinochet | ```
}else
``` |

768 | 640760da | Kenan Gillet | ```
q->erasure_count = 0;
``` |

769 | |||

770 | ```
formant_mem = q->formant_mem + 10;
``` |
||

771 | cf139541 | Reynaldo H. Verdejo Pinochet | for(i=0; i<4; i++) |

772 | { |
||

773 | 640760da | Kenan Gillet | interpolate_lpc(q, quantized_lspf, lpc, i); |

774 | cf139541 | Reynaldo H. Verdejo Pinochet | ff_celp_lp_synthesis_filterf(formant_mem, lpc, outbuffer + i * 40, 40, |

775 | ```
10);
``` |
||

776 | 640760da | Kenan Gillet | ```
formant_mem += 40;
``` |

777 | } |
||

778 | memcpy(q->formant_mem, q->formant_mem + 160, 10 * sizeof(float)); |
||

779 | |||

780 | ```
// FIXME: postfilter and final gain control should be here.
``` |
||

781 | ```
// TIA/EIA/IS-733 2.4.8.6
``` |
||

782 | |||

783 | ```
formant_mem = q->formant_mem + 10;
``` |
||

784 | cf139541 | Reynaldo H. Verdejo Pinochet | for(i=0; i<160; i++) |

785 | *outbuffer++ = av_clipf(*formant_mem++, QCELP_CLIP_LOWER_BOUND, |
||

786 | QCELP_CLIP_UPPER_BOUND); |
||

787 | 640760da | Kenan Gillet | |

788 | ```
memcpy(q->prev_lspf, quantized_lspf, sizeof(q->prev_lspf));
``` |
||

789 | q->prev_bitrate = q->bitrate; |
||

790 | |||

791 | *data_size = 160 * sizeof(*outbuffer); |
||

792 | |||

793 | ```
return *data_size;
``` |
||

794 | } |
||

795 | |||

796 | 200de8c6 | Kenan Gillet | AVCodec qcelp_decoder = |

797 | { |
||

798 | ```
.name = "qcelp",
``` |
||

799 | .type = CODEC_TYPE_AUDIO, |
||

800 | .id = CODEC_ID_QCELP, |
||

801 | .init = qcelp_decode_init, |
||

802 | .decode = qcelp_decode_frame, |
||

803 | ```
.priv_data_size = sizeof(QCELPContext),
``` |
||

804 | ```
.long_name = NULL_IF_CONFIG_SMALL("QCELP / PureVoice"),
``` |
||

805 | }; |