Browse Source

Implement G729 AnnexB : VAD/DTX/CNG

- VAD algo is actually the variant described in G729 Appendix II
+ move headers to src files
pull/2/head
Johan Pascal 11 years ago
parent
commit
843c130cf7
59 changed files with 2809 additions and 305 deletions
  1. +0
    -30
      include/Makefile.am
  2. +2
    -1
      include/bcg729/decoder.h
  3. +8
    -3
      include/bcg729/encoder.h
  4. +0
    -32
      include/computeLP.h
  5. +6
    -3
      msbcg729/bcg729_dec.c
  6. +24
    -9
      msbcg729/bcg729_enc.c
  7. +3
    -0
      src/CMakeLists.txt
  8. +3
    -3
      src/LP2LSPConversion.h
  9. +0
    -0
      src/LPSynthesisFilter.h
  10. +206
    -1
      src/LSPQuantization.c
  11. +12
    -0
      src/LSPQuantization.h
  12. +4
    -1
      src/Makefile.am
  13. +0
    -0
      src/adaptativeCodebookSearch.h
  14. +0
    -0
      src/basicOperationsMacros.h
  15. +294
    -0
      src/cng.c
  16. +54
    -0
      src/cng.h
  17. +63
    -3
      src/codebooks.c
  18. +11
    -0
      src/codebooks.h
  19. +25
    -0
      src/codecParameters.h
  20. +0
    -0
      src/computeAdaptativeCodebookGain.h
  21. +121
    -79
      src/computeLP.c
  22. +49
    -0
      src/computeLP.h
  23. +0
    -0
      src/computeWeightedSpeech.h
  24. +50
    -34
      src/decodeAdaptativeCodeVector.c
  25. +13
    -0
      src/decodeAdaptativeCodeVector.h
  26. +0
    -0
      src/decodeFixedCodeVector.h
  27. +0
    -0
      src/decodeGains.h
  28. +65
    -46
      src/decodeLSP.c
  29. +14
    -0
      src/decodeLSP.h
  30. +79
    -25
      src/decoder.c
  31. +431
    -0
      src/dtx.c
  32. +61
    -0
      src/dtx.h
  33. +108
    -4
      src/encoder.c
  34. +0
    -0
      src/findOpenLoopPitchDelay.h
  35. +0
    -0
      src/fixedCodebookSearch.h
  36. +17
    -1
      src/fixedPointMacros.h
  37. +0
    -0
      src/floatingPointMacros.h
  38. +0
    -0
      src/g729FixedPointMath.h
  39. +0
    -0
      src/gainQuantization.h
  40. +0
    -0
      src/interpolateqLSP.h
  41. +0
    -0
      src/postFilter.h
  42. +0
    -0
      src/postProcessing.h
  43. +0
    -0
      src/preProcessing.h
  44. +0
    -0
      src/qLSP2LP.h
  45. +60
    -0
      src/typedef.h
  46. +56
    -0
      src/utils.c
  47. +35
    -0
      src/utils.h
  48. +422
    -0
      src/vad.c
  49. +42
    -0
      src/vad.h
  50. +5
    -2
      test/bin/Makefile.am
  51. +143
    -0
      test/src/CNGdecoderTest.c
  52. +8
    -1
      test/src/computeLPTest.c
  53. +105
    -0
      test/src/computeNoiseExcitationTest.c
  54. +1
    -1
      test/src/decoderMultiChannelTest.c
  55. +2
    -2
      test/src/decoderTest.c
  56. +15
    -11
      test/src/encoderMultiChannelTest.c
  57. +28
    -12
      test/src/encoderTest.c
  58. +161
    -0
      test/src/encoderVADTest.c
  59. +3
    -1
      test/testCampaign

+ 0
- 30
include/Makefile.am View File

@ -1,31 +1 @@
SUBDIRS = bcg729
include_HEADERS= adaptativeCodebookSearch.h \
basicOperationsMacros.h \
codebooks.h \
codecParameters.h \
computeAdaptativeCodebookGain.h \
computeLP.h \
computeWeightedSpeech.h \
decodeAdaptativeCodeVector.h \
decodeFixedCodeVector.h \
decodeGains.h \
decodeLSP.h \
findOpenLoopPitchDelay.h \
fixedCodebookSearch.h \
fixedPointMacros.h \
floatingPointMacros.h \
g729FixedPointMath.h \
gainQuantization.h \
interpolateqLSP.h \
LP2LSPConversion.h \
LPSynthesisFilter.h \
LSPQuantization.h \
postFilter.h \
postProcessing.h \
preProcessing.h \
qLSP2LP.h \
typedef.h \
utils.h
EXTRA_DIST=$(include_HEADERS)

+ 2
- 1
include/bcg729/decoder.h View File

@ -51,8 +51,9 @@ BCG729_VISIBILITY void closeBcg729DecoderChannel(bcg729DecoderChannelContextStru
/* -(i) decoderChannelContext : the channel context data */
/* -(i) bitStream : 15 parameters on 80 bits */
/* -(i) frameErased: flag: true, frame has been erased */
/* -(i) SIDFrameFlag: flag: true, frame is a SID one */
/* -(o) signal : a decoded frame 80 samples (16 bits PCM) */
/* */
/*****************************************************************************/
BCG729_VISIBILITY void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uint8_t bitStream[], uint8_t frameErasureFlag, int16_t signal[]);
BCG729_VISIBILITY void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uint8_t bitStream[], uint8_t frameErasureFlag, uint8_t SIDFrameFlag, int16_t signal[]);
#endif /* ifndef DECODER_H */

+ 8
- 3
include/bcg729/encoder.h View File

@ -31,11 +31,13 @@ typedef struct bcg729EncoderChannelContextStruct_struct bcg729EncoderChannelCont
/*****************************************************************************/
/* initBcg729EncoderChannel : create context structure and initialise it */
/* parameters: */
/* -(i) enanbleVAD : flag set to 1: VAD/DTX is enabled */
/* return value : */
/* - the encoder channel context data */
/* */
/*****************************************************************************/
BCG729_VISIBILITY bcg729EncoderChannelContextStruct *initBcg729EncoderChannel();
BCG729_VISIBILITY bcg729EncoderChannelContextStruct *initBcg729EncoderChannel(uint8_t enableVAD);
/*****************************************************************************/
/* closeBcg729EncoderChannel : free memory of context structure */
@ -51,8 +53,11 @@ BCG729_VISIBILITY void closeBcg729EncoderChannel(bcg729EncoderChannelContextStru
/* -(i) encoderChannelContext : context for this encoder channel */
/* -(i) inputFrame : 80 samples (16 bits PCM) */
/* -(o) bitStream : The 15 parameters for a frame on 80 bits */
/* on 80 bits (5 16bits words) */
/* on 80 bits (5 16bits words) for voice frame, 4 on 2 byte for */
/* noise frame, 0 for untransmitted frames */
/* -(o) bitStreamLength : actual length of output, may be 0, 2 or 10 */
/* if VAD/DTX is enabled */
/* */
/*****************************************************************************/
BCG729_VISIBILITY void bcg729Encoder(bcg729EncoderChannelContextStruct *encoderChannelContext, int16_t inputFrame[], uint8_t bitStream[]);
BCG729_VISIBILITY void bcg729Encoder(bcg729EncoderChannelContextStruct *encoderChannelContext, int16_t inputFrame[], uint8_t bitStream[], uint8_t *bitStreamLength);
#endif /* ifndef ENCODER_H */

+ 0
- 32
include/computeLP.h View File

@ -1,32 +0,0 @@
/*
computeLP.h
Copyright (C) 2011 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef COMPUTELP_H
#define COMPUTELP_H
/*****************************************************************************/
/* computeLP : As described in spec 3.2.1 and 3.2.2 : Windowing, */
/* Autocorrelation and Levinson-Durbin algorithm */
/* parameters: */
/* -(i) signal: 240 samples in Q0, the last 40 are from next frame */
/* -(o) LPCoefficientsQ12: 10 LP coefficients in Q12 */
/* */
/*****************************************************************************/
void computeLP(word16_t signal[], word16_t LPCoefficientsQ12[]);
#endif /* ifndef COMPUTELP_H */

+ 6
- 3
msbcg729/bcg729_dec.c View File

@ -26,6 +26,7 @@
/* signal and bitstream frame size in byte */
#define SIGNAL_FRAME_SIZE 160
#define BITSTREAM_FRAME_SIZE 10
#define NOISE_BITSTREAM_FRAME_SIZE 2
/* decoder struct: context for decoder channel and concealment */
struct bcg729Decoder_struct {
@ -49,11 +50,13 @@ static void filter_process(MSFilter *f){
while((inputMessage=ms_queue_get(f->inputs[0]))) {
while(inputMessage->b_rptr<inputMessage->b_wptr) {
/* if remaining data in RTP payload have the size of a SID frame it must be one, see RFC3551 section 4.5.6 : any SID frame must be the last one of the RPT payload */
uint8_t SIDFrameFlag = ((inputMessage->b_wptr-inputMessage->b_rptr)==NOISE_BITSTREAM_FRAME_SIZE)?1:0;
outputMessage = allocb(SIGNAL_FRAME_SIZE,0);
mblk_meta_copy(inputMessage, outputMessage);
bcg729Decoder(obj->decoderChannelContext, inputMessage->b_rptr, 0, (int16_t *)(outputMessage->b_wptr));
bcg729Decoder(obj->decoderChannelContext, inputMessage->b_rptr, 0, SIDFrameFlag, (int16_t *)(outputMessage->b_wptr));
outputMessage->b_wptr+=SIGNAL_FRAME_SIZE;
inputMessage->b_rptr+=BITSTREAM_FRAME_SIZE;
inputMessage->b_rptr += (SIDFrameFlag==1)?NOISE_BITSTREAM_FRAME_SIZE:BITSTREAM_FRAME_SIZE;
ms_queue_put(f->outputs[0],outputMessage);
ms_concealer_inc_sample_time(obj->concealer,f->ticker->time,10, 1);
}
@ -62,7 +65,7 @@ static void filter_process(MSFilter *f){
if (ms_concealer_context_is_concealement_required(obj->concealer, f->ticker->time)) {
outputMessage = allocb(SIGNAL_FRAME_SIZE,0);
bcg729Decoder(obj->decoderChannelContext, NULL, 1, (int16_t *)(outputMessage->b_wptr));
bcg729Decoder(obj->decoderChannelContext, NULL, 1, 0, (int16_t *)(outputMessage->b_wptr));
outputMessage->b_wptr+=SIGNAL_FRAME_SIZE;
mblk_set_plc_flag(outputMessage, 1);
ms_queue_put(f->outputs[0],outputMessage);


+ 24
- 9
msbcg729/bcg729_enc.c View File

@ -24,11 +24,12 @@
/*filter common method*/
struct bcg729Encoder_struct {
bcg729EncoderChannelContextStruct *encoderChannelContext;
bcg729EncoderChannelContextStruct *encoderChannelContext;
MSBufferizer *bufferizer;
unsigned char ptime;
unsigned char max_ptime;
uint32_t ts;
uint8_t enableVAD;
};
static void filter_init(MSFilter *f){
@ -37,12 +38,13 @@ static void filter_init(MSFilter *f){
obj = (struct bcg729Encoder_struct*) f->data;
obj->ptime=20;
obj->max_ptime=100;
obj->enableVAD=0;
}
static void filter_preprocess(MSFilter *f){
struct bcg729Encoder_struct* obj= (struct bcg729Encoder_struct*) f->data;
obj->encoderChannelContext = initBcg729EncoderChannel(); /* initialize bcg729 encoder, return context */
obj->encoderChannelContext = initBcg729EncoderChannel(obj->enableVAD); /* initialize bcg729 encoder, return context */
obj->bufferizer=ms_bufferizer_new();
}
@ -59,17 +61,23 @@ static void filter_process(MSFilter *f){
/* process ptimes ms of data : (ptime in ms)/1000->ptime is seconds * 8000(sample rate) * 2(byte per sample) */
while(ms_bufferizer_get_avail(obj->bufferizer)>=obj->ptime*16){
uint16_t totalPacketDataLength = 0;
uint8_t bitStreamLength = 0;
outputMessage = allocb(obj->ptime,0); /* output bitStream is 80 bits long * number of samples */
/* process buffer in 10 ms frames */
for (bufferIndex=0; bufferIndex<obj->ptime; bufferIndex+=10) {
/* RFC3551 section 4.5.6 we must end the RTP payload of G729 frames when transmitting a SID frame : bitStreamLength == 2 */
for (bufferIndex=0; (bufferIndex<obj->ptime) && (bitStreamLength!=2); bufferIndex+=10) {
ms_bufferizer_read(obj->bufferizer,inputBuffer,160);
bcg729Encoder(obj->encoderChannelContext, (int16_t *)inputBuffer, outputMessage->b_wptr);
outputMessage->b_wptr+=10;
bcg729Encoder(obj->encoderChannelContext, (int16_t *)inputBuffer, outputMessage->b_wptr, &bitStreamLength);
outputMessage->b_wptr+=bitStreamLength;
totalPacketDataLength+=bitStreamLength;
}
obj->ts+=bufferIndex*8;
/* do not enqueue the message if no data out (DTX untransmitted frames) */
if (totalPacketDataLength>0) {
mblk_set_timestamp_info(outputMessage,obj->ts);
ms_queue_put(f->outputs[0],outputMessage);
}
obj->ts+=obj->ptime*8;
mblk_set_timestamp_info(outputMessage,obj->ts);
ms_queue_put(f->outputs[0],outputMessage);
}
}
@ -110,7 +118,14 @@ static int filter_add_fmtp(MSFilter *f, void *arg){
}
ms_message("MSBCG729Enc: got ptime=%i",obj->ptime);
} else if (fmtp_get_value(fmtp,"annexb",buf,sizeof(buf))){
if (strncmp(buf, "yes",3)) {
obj->enableVAD = 1;
ms_message("MSBCG729Enc: enable VAD/DTX - AnnexB");
}
}
/* parse annexB param here */
return 0;
}


+ 3
- 0
src/CMakeLists.txt View File

@ -44,6 +44,9 @@ set(BCG729_SOURCE_FILES
preProcessing.c
qLSP2LP.c
utils.c
cng.c
dtx.c
vad.c
)
add_library(bcg729 SHARED ${BCG729_SOURCE_FILES})


include/LP2LSPConversion.h → src/LP2LSPConversion.h View File


include/LPSynthesisFilter.h → src/LPSynthesisFilter.h View File


+ 206
- 1
src/LSPQuantization.c View File

@ -39,6 +39,211 @@ void initLSPQuantization(bcg729EncoderChannelContextStruct *encoderChannelContex
}
return;
}
/**********************************************************************************/
/* noiseLSPQuantization : Convert LSP to LSF, Quantize LSF and find L parameters, */
/* qLSF->qLSP as described in spec A3.2.4 */
/* parameters: */
/* -(i/o) previousqLSF : 4 previousqLSF, is updated by this function */
/* -(i) LSPCoefficients : 10 LSP coefficients in Q15 */
/* -(o) qLSPCoefficients : 10 qLSP coefficients in Q15 */
/* -(o) parameters : 3 parameters L0, L1, L2 */
/* */
/**********************************************************************************/
void noiseLSPQuantization(word16_t previousqLSF[MA_MAX_K][NB_LSP_COEFF], word16_t LSPCoefficients[], word16_t qLSPCoefficients[], uint8_t parameters[])
{
int i,j;
int L0;
word16_t LSF[NB_LSP_COEFF]; /* LSF coefficients in Q2.13 range [0, Pi[ */
word16_t weights[NB_LSP_COEFF]; /* weights in Q11 */
word16_t weightsThreshold[NB_LSP_COEFF]; /* store in Q13 the threshold used to compute the weights */
word16_t L1index[L0_RANGE];
word16_t L2index[L0_RANGE];
word32_t weightedMeanSquareError[L0_RANGE];
word16_t quantizerOutput[NB_LSP_COEFF];
word16_t qLSF[NB_LSP_COEFF];
/*** compute LSF in Q2.13 : lsf = arcos(lsp) range [0, Pi[ spec 3.2.4 eq18 ***/
for (i=0; i<NB_LSP_COEFF; i++) {
LSF[i] = g729Acos_Q15Q13(LSPCoefficients[i]);
}
/*** compute the weights vector as in spec 3.2.4 eq22 ***/
weightsThreshold[0] = SUB16(LSF[1], OO4PIPLUS1_IN_Q13);
for (i=1; i<NB_LSP_COEFF-1; i++) {
weightsThreshold[i] = SUB16(SUB16(LSF[i+1], LSF[i-1]), ONE_IN_Q13);
}
weightsThreshold[NB_LSP_COEFF-1] = SUB16(O92PIMINUS1_IN_Q13, LSF[NB_LSP_COEFF-2]);
for (i=0; i<NB_LSP_COEFF; i++) {
if (weightsThreshold[i]>0) {
weights[i] = ONE_IN_Q11;
} else {
weights[i] = (word16_t)SATURATE(ADD32(PSHR(MULT16_16(MULT16_16_Q13(weightsThreshold[i], weightsThreshold[i]), 10), 2), ONE_IN_Q11), MAXINT16);
}
}
weights[4] = MULT16_16_Q14(weights[4], ONE_POINT_2_IN_Q14);
weights[5] = MULT16_16_Q14(weights[5], ONE_POINT_2_IN_Q14);
/*** compute the coefficients for the two noise noise MA Predictors ***/
for (L0=0; L0<L0_RANGE; L0++) {
/* compute the target Vector (l) to be quantized as in spec 3.2.4 eq23 */
word16_t targetVector[NB_LSP_COEFF]; /* vector to be quantized in Q13 */
word32_t meanSquareDiff = MAXINT32;
word16_t quantizedVector[NB_LSP_COEFF]; /* in Q13, the current state of quantized vector */
for (i=0; i<NB_LSP_COEFF; i++) {
word32_t acc = SHL(LSF[i],15); /* acc in Q2.28 */
for (j=0; j<MA_MAX_K; j++) {
acc = MSU16_16(acc, previousqLSF[j][i], noiseMAPredictor[L0][j][i]); /* previousqLSF in Q2.13 and MAPredictor in Q0.15-> acc in Q2.28 */
}
targetVector[i] = MULT16_16_Q12((word16_t)PSHR(acc, 15), invNoiseMAPredictorSum[L0][i]); /* acc->Q13 and invMAPredictorSum in Q12 -> targetVector in Q13 */
}
/* find closest match for predictionError (minimize mean square diff) in L1 subset codebook: 32 entries from L1 codebook */
for (i=0; i<NOISE_L1_RANGE; i++) {
word32_t acc = 0;
for (j=0; j<NB_LSP_COEFF; j++) {
word16_t difftargetVectorL1 = SATURATE(SUB32(targetVector[j], L1[L1SubsetIndex[i]][j]), MAXINT16);
acc = MAC16_16(acc, difftargetVectorL1, difftargetVectorL1);
}
if (acc<meanSquareDiff) {
meanSquareDiff = acc;
L1index[L0] = i;
}
}
/* find the closest match in L2 subset wich will minimise the weighted sum of (targetVector - L1 result - L2)^2 */
/* using eq20, eq21 and eq23 in spec 3.2.4 -> l[i] - l^[i] = (wi - w^[i])/(1-SumMAPred[i]) but ITU code ignores this denominator */
/* works on the first five coefficients only */
meanSquareDiff = MAXINT32;
for (i=0; i<NOISE_L2_RANGE; i++) {
word32_t acc = 0;
for (j=0; j<NB_LSP_COEFF/2; j++) {
/* commented code : compute in the same way of the ITU code: ignore the denonimator and minimize (wi - w^[i])/(1-SumMAPred[i]) instead of (wi - w^[i]) square sum */
word16_t difftargetVectorL1L2 = SATURATE(MULT16_16_Q15(SUB32(SUB32(targetVector[j], L1[L1SubsetIndex[L1index[L0]]][j]), L2L3[L2SubsetIndex[i]][j]), noiseMAPredictorSum[L0][j]), MAXINT16); /* targetVector, L1 and L2L3 in Q13 -> result in Q13 */
acc = MAC16_16(acc, difftargetVectorL1L2, MULT16_16_Q11(difftargetVectorL1L2, weights[j])); /* weights in Q11, diff in Q13 */
}
for (j=NB_LSP_COEFF/2; j<NB_LSP_COEFF; j++) {
word16_t difftargetVectorL1L3 = SATURATE(MULT16_16_Q15(SUB32(SUB32(targetVector[j], L1[L1SubsetIndex[L1index[L0]]][j]), L2L3[L3SubsetIndex[i]][j]), noiseMAPredictorSum[L0][j]), MAXINT16); /* targetVector, L1 and L2L3 in Q13 -> result in Q13 */
acc = MAC16_16(acc, difftargetVectorL1L3, MULT16_16_Q11(difftargetVectorL1L3, weights[j])); /* weights in Q11, diff in Q13 */
}
if (acc<meanSquareDiff) {
meanSquareDiff = acc;
L2index[L0] = i;
}
}
/* compute the quantized vector L1+L2/L3 and rearrange it as specified in spec 3.2.4 */
/* Note: according to the spec, the rearrangement shall be done on each candidate while looking for best match, but the ITU code does it after picking the best match and so we do */
for (i=0; i<NB_LSP_COEFF/2; i++) {
quantizedVector[i] = ADD16(L1[L1SubsetIndex[L1index[L0]]][i], L2L3[L2SubsetIndex[L2index[L0]]][i]);
}
for (i=NB_LSP_COEFF/2; i<NB_LSP_COEFF; i++) {
quantizedVector[i] = ADD16(L1[L1index[L0]][i], L2L3[L3SubsetIndex[L2index[L0]]][i]);
}
/* rearrange with a minimum distance of 0.0012 */
for (i=1; i<NB_LSP_COEFF/2; i++) {
if (quantizedVector[i-1]>SUB16(quantizedVector[i],GAP1)) {
quantizedVector[i-1] = PSHR(SUB16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP1), 1);
quantizedVector[i] = PSHR(ADD16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP1), 1);
}
}
for (i=NB_LSP_COEFF/2+1; i<NB_LSP_COEFF; i++) {
if (quantizedVector[i-1]>SUB16(quantizedVector[i],GAP1)) {
quantizedVector[i-1] = PSHR(SUB16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP1), 1);
quantizedVector[i] = PSHR(ADD16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP1), 1);
}
}
/* rearrange the whole quantizedVector with a distance of 0.0006 */
for (i=1; i<NB_LSP_COEFF; i++) {
if (quantizedVector[i-1]>SUB16(quantizedVector[i],GAP2)) {
quantizedVector[i-1] = PSHR(SUB16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP2), 1);
quantizedVector[i] = PSHR(ADD16(ADD16(quantizedVector[i], quantizedVector[i-1]), GAP2), 1);
}
}
/* compute the weighted mean square distance using the final quantized vector according to eq21 */
weightedMeanSquareError[L0]=0;
for (i=0; i<NB_LSP_COEFF; i++) {
word16_t difftargetVectorQuantizedVector = SATURATE(MULT16_16_Q15(SUB32(targetVector[i], quantizedVector[i]), noiseMAPredictorSum[L0][i]), MAXINT16); /* targetVector and quantizedVector in Q13 -> result in Q13 */
weightedMeanSquareError[L0] = MAC16_16(weightedMeanSquareError[L0], difftargetVectorQuantizedVector, MULT16_16_Q11(difftargetVectorQuantizedVector, weights[i])); /* weights in Q11, diff in Q13 */
}
}
/* now select L0 and copy the selected coefficients to the output buffer */
if (weightedMeanSquareError[0]<weightedMeanSquareError[1]) {
parameters[0] = 0;
parameters[1] = L1index[0];
parameters[2] = L2index[0];
} else {
parameters[0] = 1;
parameters[1] = L1index[1];
parameters[2] = L2index[1];
}
/*** Compute the quantized LSF from the L coefficients ***/
/* reconstruct vector from the codebooks using the selected parameters spec 3.2.4 eq19 */
for (i=0; i<NB_LSP_COEFF/2; i++) {
quantizerOutput[i] = ADD16(L1[L1SubsetIndex[parameters[1]]][i], L2L3[L2SubsetIndex[parameters[2]]][i]); /* codebooks are in Q2.13 for L1 and Q0.13 for L2L3, due to actual values stored in the codebooks, result in Q2.13 */
}
for ( i=NB_LSP_COEFF/2; i<NB_LSP_COEFF; i++) {
quantizerOutput[i] = ADD16(L1[L1SubsetIndex[parameters[1]]][i], L2L3[L3SubsetIndex[parameters[2]]][i]); /* same as previous, output in Q2.13 */
}
/* rearrange in order to have a minimum distance between two consecutives coefficients spec 3.2.4 */
rearrangeCoefficients(quantizerOutput, GAP1);
rearrangeCoefficients(quantizerOutput, GAP2); /* currentqLSF still in Q2.13 */
/* compute qLSF spec 3.2.4 eq20 */
for (i=0; i<NB_LSP_COEFF; i++) {
word32_t acc = MULT16_16(noiseMAPredictorSum[parameters[0]][i], quantizerOutput[i]); /* (1 - ∑Pi,k)*lˆi(m) Q15 * Q13 -> Q28 */
for (j=0; j<MA_MAX_K; j++) {
acc = MAC16_16(acc, noiseMAPredictor[parameters[0]][j][i], previousqLSF[j][i]);
}
/* acc in Q2.28, shift back the acc to a Q2.13 with rounding */
qLSF[i] = (word16_t)PSHR(acc, 15); /* qLSF in Q2.13 */
}
/* update the previousqLSF buffer with current quantizer output */
for (i=MA_MAX_K-1; i>0; i--) {
memcpy(previousqLSF[i], previousqLSF[i-1], NB_LSP_COEFF*sizeof(word16_t));
}
memcpy(previousqLSF[0], quantizerOutput, NB_LSP_COEFF*sizeof(word16_t));
/*** qLSF stability check ***/
insertionSort(qLSF, NB_LSP_COEFF);
/* check for low limit on qLSF[0] */
if (qLSF[1]<qLSF_MIN) {
qLSF[1] = qLSF_MIN;
}
/* check and rectify minimum distance between two consecutive qLSF */
for (i=0; i<NB_LSP_COEFF-1; i++) {
if (SUB16(qLSF[i+1],qLSF[i])<MIN_qLSF_DISTANCE) {
qLSF[i+1] = qLSF[i]+MIN_qLSF_DISTANCE;
}
}
/* check for upper limit on qLSF[NB_LSP_COEFF-1] */
if (qLSF[NB_LSP_COEFF-1]>qLSF_MAX) {
qLSF[NB_LSP_COEFF-1] = qLSF_MAX;
}
/* convert qLSF to qLSP: qLSP = cos(qLSF) */
for (i=0; i<NB_LSP_COEFF; i++) {
qLSPCoefficients[i] = g729Cos_Q13Q15(qLSF[i]); /* ouput in Q0.15 */
}
return;
}
/*****************************************************************************/
/* LSPQuantization : Convert LSP to LSF, Quantize LSF and find L parameters, */
@ -46,7 +251,7 @@ void initLSPQuantization(bcg729EncoderChannelContextStruct *encoderChannelContex
/* parameters: */
/* -(i/o) encoderChannelContext : the channel context data */
/* -(i) LSPCoefficients : 10 LSP coefficients in Q15 */
/* -(i) qLSPCoefficients : 10 qLSP coefficients in Q15 */
/* -(o) qLSPCoefficients : 10 qLSP coefficients in Q15 */
/* -(o) parameters : 4 parameters L0, L1, L2, L3 */
/* */
/*****************************************************************************/


include/LSPQuantization.h → src/LSPQuantization.h View File


+ 4
- 1
src/Makefile.am View File

@ -26,7 +26,10 @@ libbcg729_la_SOURCES= LP2LSPConversion.c \
postProcessing.c \
preProcessing.c \
qLSP2LP.c \
utils.c
utils.c \
cng.c \
vad.c \
dtx.c
libbcg729_la_LDFLAGS= -no-undefined


include/adaptativeCodebookSearch.h → src/adaptativeCodebookSearch.h View File


include/basicOperationsMacros.h → src/basicOperationsMacros.h View File


+ 294
- 0
src/cng.c View File

@ -0,0 +1,294 @@
/*
cng.c
Comfort Noise Generation
Copyright (C) 2015 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include "typedef.h"
#include "codecParameters.h"
#include "basicOperationsMacros.h"
#include "utils.h"
#include "cng.h"
#include "decodeAdaptativeCodeVector.h"
#include "decodeLSP.h"
#include "interpolateqLSP.h"
#include "qLSP2LP.h"
#include "g729FixedPointMath.h"
#include "codebooks.h"
/* buffers allocation */
static const word16_t SIDqLSPInitialValues[NB_LSP_COEFF] = {31441, 27566, 21458, 13612, 4663, -4663, -13612, -21458, -27566, -31441}; /* in Q0.15 the initials values for the previous qLSP buffer */
bcg729CNGChannelContextStruct *initBcg729CNGChannel() {
/* create the context structure */
bcg729CNGChannelContextStruct *CNGChannelContext = malloc(sizeof(bcg729CNGChannelContextStruct));
memset(CNGChannelContext, 0, sizeof(*CNGChannelContext));
memcpy(CNGChannelContext->qLSP, SIDqLSPInitialValues, NB_LSP_COEFF*sizeof(word16_t)); /* initialise the previousqLSP buffer */
return CNGChannelContext;
}
/*******************************************************************************************/
/* computeComfortNoiseExcitationVector : as is spec B4.4 and B4.5 */
/* parameters: */
/* -(i): targetGain : the gain from ea B.19 in Q3 */
/* -(i/o): randomGeneratorSeed : used to get a pseudo random number, is updated */
/* -(i/o): excitationVector in Q0, accessed in range [-L_PAST_EXCITATION,L_FRAME-1] */
/* [-154,79] */
/* */
/*******************************************************************************************/
void computeComfortNoiseExcitationVector(word16_t targetGain, uint16_t *randomGeneratorSeed, word16_t *excitationVector) {
int16_t fracPitchDelay,intPitchDelay;
uint16_t randomNumberBuffer;
uint8_t subframeIndex = 0;
int i,j;
/* shall we check targetGain is 0?? and set excitation vector[0,L_FRAME[ to 0 in this case?*/
for (subframeIndex=0; subframeIndex<L_FRAME; subframeIndex+=L_SUBFRAME) { /* process 2 subframes */
word16_t gaussianRandomExcitation[L_SUBFRAME];
word32_t Eg = 0;
word32_t Gg = 0; /* gain to be applied to the randomly generated gaussian to reach a Eg of 1/4*L_SUBFRAME*targetGain(note this doesn't appears in spec, only in ITU code)*/
word16_t Ga = 0; /* gain to be applied to adaptative subframe excitation in Q0.15 */
word32_t Ea = 0;
word32_t Ei = 0; /* inter excitation : Sum[0..39] adaptativeExcitation*fixedExcitation, defined in eq B21*/
word32_t K = 0;
word32_t Gf = 0; /* gain to be applied to the fixed codebook excitation */
word32_t x2 = 0; /* second root of the 2nd degre equation solved to get Gf */
word16_t sign[4]; /* sign of the impulses of fixed codebook excitation */
word16_t position[4]; /* positions of the impulses of fixed codebook excitation */
uint8_t deltaScaleFactor=0;
word64_t delta;
/* generate pseudo random pitch delay in range [40,103] for adaptative codebook */
randomNumberBuffer = pseudoRandom(randomGeneratorSeed); /* get 16 bits of pseudoRandom value*/
fracPitchDelay = (int16_t)(randomNumberBuffer&0x0003)-1; /* fraction part of the pitch delay shall be -1, 0 or 1 */
if (fracPitchDelay==2) fracPitchDelay = 0;
randomNumberBuffer = randomNumberBuffer>>2; /* 14 random bits left */
intPitchDelay = (randomNumberBuffer&0x003F) + 40; /* intPitchDelay in [40,103] */
randomNumberBuffer = randomNumberBuffer>>6; /* 8 random bits left */
/* generate pseudo random sign and position for fixed codebook */
position[0] = (randomNumberBuffer&0x0007)*5;
randomNumberBuffer = randomNumberBuffer>>3; /* 5 random bits left */
sign[0] = randomNumberBuffer&0x0001;
randomNumberBuffer = randomNumberBuffer>>1; /* 4 random bits left */
position[1] = (randomNumberBuffer&0x0007)*5+1;
randomNumberBuffer = randomNumberBuffer>>3; /* 1 random bits left */
sign[1] = randomNumberBuffer&0x0001,
randomNumberBuffer = pseudoRandom(randomGeneratorSeed); /* get 16 bits of pseudoRandom value*/
position[2] = (randomNumberBuffer&0x0007)*5+2;
randomNumberBuffer = randomNumberBuffer>>3; /* 13 random bits left */
sign[2] = randomNumberBuffer&0x0001;
randomNumberBuffer = randomNumberBuffer>>1; /* 12 random bits left */
position[3] = (randomNumberBuffer&0x0001)+3; /*j+3*/
randomNumberBuffer = randomNumberBuffer>>1; /* 11 random bits left */
position[3] += (randomNumberBuffer&0x0007)*5;
randomNumberBuffer = randomNumberBuffer>>3; /* 8 random bits left */
sign[3] = randomNumberBuffer&0x0001;
randomNumberBuffer = randomNumberBuffer>>1; /* 7 random bits left */
/* randomly generate Ga : adaptative gain eqB.22: max is 0,5 */
Ga = (pseudoRandom(randomGeneratorSeed)&0x1fff)<<1; /* get 16 bits of pseudoRandom value but make sure it is < 0.5 in Q15 */
/* generate gaussian random excitation : get generation algo from ITU code, no reference to this in the spec...
* Compute also the subframe energy(Sum [0..39] excitation^2) and then scale the sample to get an subframe average energy to targetGain/4 */
for (i=0; i<L_SUBFRAME; i++) {
word32_t tmpBuffer=0;
for (j=0; j<12; j++) {
tmpBuffer=ADD32(tmpBuffer, (word16_t)pseudoRandom(randomGeneratorSeed)); /* cast the unsigned 16 bits value to a signed one */
}
gaussianRandomExcitation[i]=(word16_t)(SHR(tmpBuffer,7));
Eg = MAC16_16(Eg, gaussianRandomExcitation[i], gaussianRandomExcitation[i]);
}
/* compute coefficient = 1/2*sqrt(L_SUBFRAME/gaussianRandomExcitationSubframeEnergy)*targetGain (always>0) - retrieved from ITU code, no mention of this in the spec */
/* comments in code say 1/4*sqrt() but code actually implement 1/2... */
Gg = MULT16_32_Q15(GAUSSIAN_EXCITATION_COEFF_FACTOR, g729InvSqrt_Q0Q31(Eg)); /* multiplicand in Q1.13 and Q0.31 -> result in Q1.29 */
Gg = MULT16_32_Q15(targetGain, Gg); /* multiplicand in Q3 and Q1.29 -> result in Q17 */
for (i=0; i<L_SUBFRAME; i++) {
/* operate on positive value only to avoid problem when shifting to 0 a negative one */
if (gaussianRandomExcitation[i]<0) {
gaussianRandomExcitation[i] = -SATURATE(PSHR( MULT16_32_Q15(-gaussianRandomExcitation[i], Gg), 2), MAXINT16); /* gaussianRandom in Q0, targetGain in Q17 -> result in Q2, need to shift it by 2. */
} else {
gaussianRandomExcitation[i] = PSHR( MULT16_32_Q15(gaussianRandomExcitation[i], Gg), 2);
}
}
/* generate random adaptative excitation and apply random gain Ga */
computeAdaptativeCodebookVector(excitationVector+subframeIndex, fracPitchDelay, intPitchDelay);
for (i=0; i<L_SUBFRAME; i++) {
excitationVector[i+subframeIndex] = SATURATE(MULT16_16_P15(excitationVector[i+subframeIndex], Ga), MAXINT16);
}
/* add gaussian excitation to the adaptative one */
for (i=0; i<L_SUBFRAME; i++) {
excitationVector[i+subframeIndex] = SATURATE(ADD32(excitationVector[i+subframeIndex], gaussianRandomExcitation[i]),MAXINT16);
}
/* Compute Gf: fixed excitation gain salving equation B.21 in form 4*Gf^2 + 2I*Ga*Gf + Ea*Ga^2 - K = 0 (4Gf^2 + 2bGf + c = 0)*/
/* compute Ea*Ga^2 */
for (i=0; i<L_SUBFRAME; i++) {
Ea = MAC16_16(Ea, excitationVector[i+subframeIndex], excitationVector[i+subframeIndex]); /* Ea actually contains Ea*Ga^2 as we already applied gain Ga on adaptative excitation, in Q0 */
}
/* compute Ei = I*Ga : fixed codebook hasn't been scaled yet, so it just 4 signed pulses of height 1, just get these one in our computation, in Q0 */
Ei = 0;
for (i=0; i<4; i++) {
if (sign[i] == 0) { /* negative impulse */
Ei = SUB32(Ei,excitationVector[position[i]+subframeIndex]);
} else { /* positive impulse */
Ei = ADD32(Ei,excitationVector[position[i]+subframeIndex]);
}
}
/* compute K = L_SUBRAME*targetGain in Q3 */
K = MULT16_32(targetGain, SHR(MULT16_16(L_SUBFRAME, targetGain), 3));
/* compute delta = b^2 -ac = Ei^2 + 4*(K-Ea) in Q0 */
delta = ADD64(MULT32_32(Ei,Ei), SHR(SUB64(K,SHL64((word64_t)Ea,3)),1));
if (delta<0) {
/* cancel adaptative excitation, keep gaussian one only */
for (i=0; i<L_SUBFRAME; i++) {
excitationVector[i+subframeIndex] = gaussianRandomExcitation[i];
}
/* compute again Ei and delta = Ei^2 + 3/4*K (from ITU code, no idea why) */
for (i=0; i<4; i++) {
if (sign[i] == 0) { /* negative impulse */
Ei = SUB32(Ei,excitationVector[position[i]+subframeIndex]);
} else { /* positive impulse */
Ei = ADD32(Ei,excitationVector[position[i]+subframeIndex]);
}
}
delta = ADD64(MULT32_32(Ei,Ei), MULT16_32_P15(COEFF_K,K)); /* COEFF_K is 0.75 in Q15 */
}
/* scale delta to have it fitting on 32 bits */
deltaScaleFactor = 0;
while (delta>=0x0000000080000000) {
delta = delta>>1;
deltaScaleFactor++;
}
/* deltaScaleFactor must be even */
if (deltaScaleFactor%2==1) {
delta = delta >> 1;
deltaScaleFactor++;
}
delta = g729Sqrt_Q0Q7((word32_t)delta); /* delta in Q(7-deltaScaleFactor/2)*/
/* scale b (Ei) to the same scale */
Ei = VSHR32(Ei, deltaScaleFactor/2-7);
/* compute the two roots and pick the one with smaller absolute value */
/* roots are (-b +-sqrt(delta))/a. We always have a=4, divide by four when rescaling from Q(7-deltaScaleFactor) to Q0 the final result */
Gf = SUB32(delta, Ei); /* x1 = -b + sqrt(delta) in Q(7-deltaScaleFactor) */
x2 = -ADD32(delta, Ei); /* x2 = -b - sqrt(delta) in Q(7-deltaScaleFactor) */
if (ABS(x2)<ABS(Gf)) Gf = x2; /* pick the smallest (in absolute value of the roots) */
Gf = VSHR32(Gf, 2+7-deltaScaleFactor/2); /* scale back Gf in Q0 and divide by 4 (+2 in the right shift) to get the actual root */
/* add fixed codebook excitation */
for (i=0; i<4; i++) {
if (sign[i] == 0) { /* negative impulse */
excitationVector[position[i]+subframeIndex] = SUB32(excitationVector[position[i]+subframeIndex], Gf);
} else { /* positive impulse */
excitationVector[position[i]+subframeIndex] = ADD32(excitationVector[position[i]+subframeIndex], Gf);
}
}
}
}
/*******************************************************************************************/
/* decodeSIDframe : as is spec B4.4 and B4.5 */
/* first check if we have a SID frame or a missing/untransmitted frame */
/* for SID frame get paremeters(gain and LSP) */
/* Then generate excitation vector and update qLSP */
/* parameters: */
/* -(i/o):CNGChannelContext : context containing all informations needed for CNG */
/* -(i): previousFrameIsActiveFlag: true if last decoded frame was an active one */
/* -(i): bitStream: for SID frame contains received params as in spec B4.3, */
/* NULL for missing/untransmitted frame */
/* -(i/o): excitationVector in Q0, accessed in range [-L_PAST_EXCITATION,L_FRAME-1] */
/* [-154,79] */
/* -(o): LP: 20 LP coefficients in Q12 */
/* -(i/o): previousqLSP : previous quantised LSP in Q0.15 (NB_LSP_COEFF values) */
/* -(i/o): pseudoRandomSeed : seed used in the pseudo random number generator */
/* -(i/o): previousLCodeWord: in Q2.13, buffer to store the last 4 frames codewords, */
/* used to compute the current qLSF */
/* */
/*******************************************************************************************/
void decodeSIDframe(bcg729CNGChannelContextStruct *CNGChannelContext, uint8_t previousFrameIsActiveFlag, uint8_t *bitStream, word16_t *excitationVector, word16_t *previousqLSP, word16_t *LP, uint16_t *pseudoRandomSeed, word16_t previousLCodeWord[MA_MAX_K][NB_LSP_COEFF]) {
int i;
word16_t interpolatedqLSP[NB_LSP_COEFF]; /* interpolated qLSP in Q0.15 */
/* if this is a SID frame, decode received parameters */
if (bitStream!=NULL) {
word16_t currentqLSF[NB_LSP_COEFF]; /* buffer to the current qLSF in Q2.13 */
uint8_t L0 = (bitStream[0]>>7)&0x01;
uint8_t L1Index = (bitStream[0]>>2)&0x1F;
uint8_t L2Index = ((bitStream[0]&0x03)<<2) | ((bitStream[1]>>6)&0x03);
/* retrieve gain from codebook according to Gain parameter */
CNGChannelContext->receivedSIDGain = SIDGainCodebook[((bitStream[1])>>1)&0x1F];
/* Use L1 and L2(parameter for first and second stage vector of LSF quantizer) to retrieve LSP using subset index to address the complete L1 and L2L3 codebook */
for (i=0; i<NB_LSP_COEFF/2; i++) {
currentqLSF[i]=ADD16(L1[L1SubsetIndex[L1Index]][i], L2L3[L2SubsetIndex[L2Index]][i]);
}
for (i=NB_LSP_COEFF/2; i<NB_LSP_COEFF; i++) {
currentqLSF[i]=ADD16(L1[L1SubsetIndex[L1Index]][i], L2L3[L3SubsetIndex[L2Index]][i]);
}
computeqLSF(currentqLSF, previousLCodeWord, L0, noiseMAPredictor, noiseMAPredictorSum);
/* convert qLSF to qLSP: qLSP = cos(qLSF) */
for (i=0; i<NB_LSP_COEFF; i++) {
CNGChannelContext->qLSP[i] = g729Cos_Q13Q15(currentqLSF[i]); /* ouput in Q0.15 */
}
} /* Note: Itu implementation have information to sort missing and untransmitted packets and perform reconstruction of missed SID packet when it detects it, we cannot differentiate lost vs untransmitted packet so we don't do it */
/* compute the LP coefficients */
interpolateqLSP(previousqLSP, CNGChannelContext->qLSP, interpolatedqLSP);
/* copy the current qLSP(SID ones) to previousqLSP buffer */
for (i=0; i<NB_LSP_COEFF; i++) {
previousqLSP[i] = CNGChannelContext->qLSP[i];
}
/* call the qLSP2LP function for first subframe */
qLSP2LP(interpolatedqLSP, LP);
/* call the qLSP2LP function for second subframe */
qLSP2LP(CNGChannelContext->qLSP, &(LP[NB_LSP_COEFF]));
/* apply target gain smoothing eq B.19 */
if (previousFrameIsActiveFlag) {
/* this is the first SID frame use transmitted(or recomputed from last valid frame energy) SID gain */
CNGChannelContext->smoothedSIDGain = CNGChannelContext->receivedSIDGain;
} else { /* otherwise 7/8 of last smoothed gain and 1/8 of last received gain */
CNGChannelContext->smoothedSIDGain = SUB16(CNGChannelContext->smoothedSIDGain, (CNGChannelContext->smoothedSIDGain>>3));
CNGChannelContext->smoothedSIDGain = ADD16(CNGChannelContext->smoothedSIDGain, (CNGChannelContext->receivedSIDGain>>3));
}
/* get the excitation vector */
computeComfortNoiseExcitationVector(CNGChannelContext->smoothedSIDGain, pseudoRandomSeed, excitationVector);
}

+ 54
- 0
src/cng.h View File

@ -0,0 +1,54 @@
/*
cng.h
Copyright (C) 2011 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef CNG_H
#define CNG_H
/*****************************************************************************/
/* initBcg729CNGChannel : create context structure and initialise it */
/* return value : */
/* - the CNG channel context data */
/* */
/*****************************************************************************/
bcg729CNGChannelContextStruct *initBcg729CNGChannel();
void computeComfortNoiseExcitationVector(word16_t targetGain, uint16_t *randomGeneratorSeed, word16_t *excitationVector);
/*******************************************************************************************/
/* decodeSIDframe : as is spec B4.4 and B4.5 */
/* first check if we have a SID frame or a missing/untransmitted frame */
/* for SID frame get paremeters(gain and LSP) */
/* Then generate excitation vector and update qLSP */
/* parameters: */
/* -(i/o):CNGChannelContext : context containing all informations needed for CNG */
/* -(i): previousFrameIsActiveFlag: true if last decoded frame was an active one */
/* -(i): bitStream: for SID frame contains received params as in spec B4.3, */
/* NULL for missing/untransmitted frame */
/* -(i/o): excitationVector in Q0, accessed in range [-L_PAST_EXCITATION,L_FRAME-1] */
/* [-154,79] */
/* -(i/o): previousqLSP : previous quantised LSP in Q0.15 (NB_LSP_COEFF values) */
/* -(o): LP: 20 LP coefficients in Q12 */
/* -(i/o): pseudoRandomSeed : seed used in the pseudo random number generator */
/* -(i/o): previousLCodeWord: in Q2.13, buffer to store the last 4 frames codewords, */
/* used to compute the current qLSF */
/* */
/*******************************************************************************************/
void decodeSIDframe(bcg729CNGChannelContextStruct *CNGChannelContext, uint8_t previousFrameIsActiveFlag, uint8_t *bitStream, word16_t *excitationVector, word16_t *previousqLSP, word16_t *LP, uint16_t *pseudoRandomSeed, word16_t previousLCodeWord[MA_MAX_K][NB_LSP_COEFF]);
#endif /* ifndef CNG_H */

+ 63
- 3
src/codebooks.c View File

@ -191,6 +191,12 @@ word16_t L2L3[L2_RANGE][NB_LSP_COEFF] = { /* The second stage is a 10-bit VQ spl
{ -163, 674, -11, -886, 531, -1125, -265, -242, 724, 934}
};
/* index used by CNG to reach a subset of L1, L2 and L3 codebooks */
uint8_t L1SubsetIndex[32] = {96,52,20,54,86,114,82,68,36,121,48,92,18,120,
94,124,50,125,4,100,28,76,12,117,81,22,90,116,
127,21,108,66};
uint8_t L2SubsetIndex[16] = {31,21,9,3,10,2,19,26,4,3,11,29,15,27,21,12};
uint8_t L3SubsetIndex[16] = {16,1,0,0,8,25,22,20,19,23,20,31,4,31,20,31};
word16_t MAPredictor[L0_RANGE][MA_MAX_K][NB_LSP_COEFF] = { /* the MA predictor coefficients in Q0.15 but max value < 0.5 so it fits on 15 bits */
{
@ -217,6 +223,35 @@ word16_t invMAPredictorSum[L0_RANGE][NB_LSP_COEFF] = {/* 1/(1 - Sum(MAPredictor)
{ 9202, 7320, 6788, 7738, 8170, 8154, 8856, 8818, 8366, 8544}
};
/* DTX/CNG use different values for MA predictor */
word16_t noiseMAPredictor[L0_RANGE][MA_MAX_K][NB_LSP_COEFF] = { /* the MA predictor coefficients in Q0.15 but max value < 0.5 so it fits on 15 bits */
{
{ 8421, 9109, 9175, 8965, 9034, 9057, 8765, 8775, 9106, 8673},
{ 7018, 7189, 7638, 7307, 7444, 7379, 7038, 6956, 6930, 6868},
{ 5472, 4990, 5134, 5177, 5246, 5141, 5206, 5095, 4830, 5147},
{ 4056, 3031, 2614, 3024, 2916, 2713, 3309, 3237, 2857, 3473}
},
{
{ 8145, 8617, 8779, 8648, 8718, 8829, 8713, 8705, 8806, 8231 },
{ 5894, 5525, 5603, 5773, 6016, 5968, 5896, 5835, 5721, 5707 },
{ 4568, 3765, 3605, 3963, 4144, 4038, 4225, 4139, 3914, 4255 },
{ 3643, 2455, 1944, 2466, 2438, 2259, 2798, 2775, 2479, 3124 }
}
};
word16_t noiseMAPredictorSum[L0_RANGE][NB_LSP_COEFF] = {/* 1 - Sum(MAPredictor) in Q0.15 */
{ 7798, 8447, 8205, 8293, 8126, 8477, 8447, 8703, 9043, 8604},
{10514, 12402, 12833, 11914, 11447, 11670, 11132, 11311, 11844, 11447}
};
word16_t invNoiseMAPredictorSum[L0_RANGE][NB_LSP_COEFF] = {/* 1/(1 - Sum(MAPredictor)) in Q3.12 */
{17210, 15888, 16357, 16183, 16516, 15833, 15888, 15421, 14840, 15597},
{12764, 10821, 10458, 11264, 11724, 11500, 12056, 11865, 11331, 11724}
};
/* codebook for adaptative code vector */
word16_t b30[31] = { /* in Q0.15 */
29443, 25207, 14701, 3143, -4402, -5850, -2783, 1211, 3130, 2259, 0, -1652, -1666, -464, 756, 1099, 550, -245, -634, -451, 0, 308, 296, 78, -120, -165, -79, 34, 91, 70, 0};
@ -291,6 +326,31 @@ word16_t wlp[L_LP_ANALYSIS_WINDOW] = { /* in Q15 */
23055, 22117, 21145, 20139, 19102, 18036, 16941, 15820, 14674, 13505,
12315, 11106, 9879, 8637, 7381, 6114, 4838, 3554, 2264, 971};
/* lag window as defined in spec 3.2.1 eq6 */
word16_t wlag[NB_LSP_COEFF+1] = { /* in Q15 note first coeff is not used */
32767, 32728, 32619, 32438, 32187, 31867, 31480, 31029, 30517, 29946, 29321};
/* lag window as defined in spec 3.2.1 eq6 : up to 12 values for VAD */
/* wlag[0] = 1.00000000 not used
wlag[1] = 0.99879038
wlag[2] = 0.99546897
wlag[3] = 0.98995781
wlag[4] = 0.98229337
wlag[5] = 0.97252619
wlag[6] = 0.96072036
wlag[7] = 0.94695264
wlag[8] = 0.93131179
wlag[9] = 0.91389757
wlag[10]= 0.89481968
wlag[11]= 0.87419660
wlag[12]= 0.85215437
*/
word16_t wlag[NB_LSP_COEFF+3] = { /* in Q15 note first coeff is not used */
32767, 32728, 32619, 32438, 32187, 31867, 31480, 31029, 30517, 29946, 29321, 28646, 27923};
/* quantised SID gain retrieved from ITU code, in Q3 */
word16_t SIDGainCodebook[32] = {
2, 5, 8, 13, 20, 32, 50, 64,
80, 101, 127, 160, 201, 253, 318, 401,
505, 635, 800, 1007, 1268, 1596, 2010, 2530,
3185, 4009, 5048, 6355, 8000,10071,12679,15962 };
/* Low Band Filter FIR for VAD in Q15 */
word16_t lowBandFilter[NB_LSP_COEFF+3] = {7869, 7011, 4838, 2299, 321, -660, -782, -484, -164, 3, 39, 21, 4};

include/codebooks.h → src/codebooks.h View File


include/codecParameters.h → src/codecParameters.h View File


include/computeAdaptativeCodebookGain.h → src/computeAdaptativeCodebookGain.h View File


+ 121
- 79
src/computeLP.c View File

@ -26,25 +26,117 @@
#include "computeLP.h"
/*****************************************************************************/
/* autoCorrelation2LP: convert autocorrelation coefficients to LP using */
/* Levinson-Durbin algo described in spec 3.2.2 */
/* parameters : */
/* -(i) autoCorrelationCoefficients : 11 values in variable scale */
/* scale is not needed here as a division cancel it */
/* -(o) LPCoefficientsQ12: 10 LP coefficients in Q12 */
/* -(o) reflectionCoefficient: in Q31, k[1] generated during Levinson */
/* Durbin LP coefficient generation and needed for VAD */
/* -(o) residualEnergy : with the same scale factor as input */
/* autoCorrelationCoefficients, needed by DTX */
/* */
/*****************************************************************************/
void autoCorrelation2LP(word32_t autoCorrelationCoefficients[], word16_t LPCoefficientsQ12[], word32_t *reflectionCoefficient, word32_t *residualEnergy) {
/*********************************************************************************/
/* Compute the LP Coefficient using Levinson-Durbin algo spec 3.2.2 */
/*********************************************************************************/
/* start a iteration i=2, init values as after iteration i=1 : */
/* a[0] = 1 */
/* a[1] = -r1/r0 */
/* E = r0(1 - a[1]^2) */
/* */
/* iterations i = 2..10 */
/* sum = r[i] + ∑ a[j]*r[i-j] with j = 1..i-1 (a[0] is always 1) */
/* a[i] = -sum/E */
/* iterations j = 1..i-1 */
/* a[j] += a[i]*a{i-1}[i-j] use a{i-1}: from previous iteration */
/* E *=(1-a[i]^2) */
/* */
/* r in Q31 (normalised) stored in array autoCorrelationCoefficients */
/* E in Q31 (can't be > 1) */
/* sum in Q27 (sum can't be > 1 but intermediate accumulation can) */
/* a in Q4.27 with full range possible */
/* Note: during iteration, current a[i] is in Q31 (can't be >1) and is */
/* set to Q27 at the end of current iteration */
/* */
/*********************************************************************************/
word32_t previousIterationLPCoefficients[NB_LSP_COEFF+1]; /* to compute a[]*/
word32_t LPCoefficients[NB_LSP_COEFF+1]; /* in Q4.27 */
word32_t E = 0; /* in Q31 */
word32_t sum = 0; /* in Q27 */
int i,j;
/* init */
LPCoefficients[0] = ONE_IN_Q27;
LPCoefficients[1] = -DIV32_32_Q27(autoCorrelationCoefficients[1], autoCorrelationCoefficients[0]); /* result in Q27(but<1) */
/* E = r0(1 - a[1]^2) in Q31 */
E = MULT32_32_Q31(autoCorrelationCoefficients[0], SUB32(ONE_IN_Q31, MULT32_32_Q23(LPCoefficients[1], LPCoefficients[1]))); /* LPCoefficient[1] is in Q27, using a Q23 operation will result in a Q31 variable */
for (i=2; i<NB_LSP_COEFF+1; i++) {
/* update the previousIterationLPCoefficients needed for this one */
for (j=1; j<i; j++) {
previousIterationLPCoefficients[j] = LPCoefficients[j];
}
/* sum = r[i] + ∑ a[j]*r[i-j] with j = 1..i-1 (a[0] is always 1) */
sum = 0;
for (j=1; j<i; j++) {
sum = MAC32_32_Q31(sum, LPCoefficients[j], autoCorrelationCoefficients[i-j]);/* LPCoefficients in Q27, autoCorrelation in Q31 -> result in Q27 -> sum in Q27 */
}
sum = ADD32(SHL(sum, 4), autoCorrelationCoefficients[i]); /* set sum in Q31 and add r[0] */
/* a[i] = -sum/E */
LPCoefficients[i] = -DIV32_32_Q31(sum,E); /* LPCoefficient of current iteration is in Q31 for now, it will be set to Q27 at the end of this iteration */
if (i==2) { /* parameter k[1] from eq8 in 3.2.2 needed by VAD */
*reflectionCoefficient = LPCoefficients[i];
}
/* iterations j = 1..i-1 */
/* a[j] += a[i]*a[i-j] */
for (j=1; j<i; j++) {
LPCoefficients[j] = MAC32_32_Q31(LPCoefficients[j], LPCoefficients[i], previousIterationLPCoefficients[i-j]); /*LPCoefficients in Q27 except for LPCoefficients[i] in Q31 */
}
/* E *=(1-a[i]^2) */
E = MULT32_32_Q31(E, SUB32(ONE_IN_Q31, MULT32_32_Q31(LPCoefficients[i], LPCoefficients[i]))); /* all in Q31 */
/* set LPCoefficients[i] from Q31 to Q27 */
LPCoefficients[i] = SHR(LPCoefficients[i], 4);
}
*residualEnergy = E;
/* convert with rounding the LP Coefficients form Q27 to Q12, ignore first coefficient which is always 1 */
for (i=0; i<NB_LSP_COEFF; i++) {
LPCoefficientsQ12[i] = (word16_t)SATURATE(PSHR(LPCoefficients[i+1], 15), MAXINT16);
}
}
/*****************************************************************************/
/* computeLP : As described in spec 3.2.1 and 3.2.2 : Windowing, */
/* Autocorrelation and Levinson-Durbin algorithm */
/* parameters: */
/* -(i) signal: 240 samples in Q0, the last 40 are from next frame */
/* -(o) LPCoefficientsQ12: 10 LP coefficients in Q12 */
/* */
/* -(o) reflectionCoefficient: in Q31, k[1] generated during Levinson */
/* Durbin LP coefficient generation and needed for VAD */
/* -(o) autoCorrelationCoefficients : used internally but needed by VAD */
/* scale is variable */
/* -(o) noLagautoCorrelationCoefficients : needed by DTX */
/* scale is variable */
/* -(o) autoCorrelationCoefficientsScale : scale factor of previous buf */
/* -(i) autoCorrelationCoefficientsNumber number of coeff to be computed*/
/* 13 if we are using them for VAD, only 11 otherwise */
/*****************************************************************************/
void computeLP(word16_t signal[], word16_t LPCoefficientsQ12[])
void computeLP(word16_t signal[], word16_t LPCoefficientsQ12[], word32_t *reflectionCoefficient, word32_t autoCorrelationCoefficients[], word32_t noLagAutocorrelationCoefficients[], int8_t *autoCorrelationCoefficientsScale, uint8_t autoCorrelationCoefficientsNumber)
{
int i,j;
word16_t windowedSignal[L_LP_ANALYSIS_WINDOW];
word32_t autoCorrelationCoefficient[NB_LSP_COEFF+1];
word64_t acc64=0; /* acc on 64 bits */
int rightShiftToNormalise=0;
word32_t previousIterationLPCoefficients[NB_LSP_COEFF+1]; /* to compute a[]*/
word32_t LPCoefficients[NB_LSP_COEFF+1]; /* in Q4.27 */
word32_t sum = 0; /* in Q27 */
word32_t E = 0; /* in Q31 */
word32_t residualEnergy; /* interally compute by autoCorrelation2LP and extracted for DTX only, useless here */
/*********************************************************************/
/* Compute the windowed signal according to spec 3.2.1 eq4 */
@ -56,9 +148,9 @@ void computeLP(word16_t signal[], word16_t LPCoefficientsQ12[])
/*********************************************************************************/
/* Compute the autoCorrelation coefficients r[0..10] according to spec 3.2.1 eq5 */
/*********************************************************************************/
/* Compute autoCorrelationCoefficient[0] first as it is the highest number and normalise it on 32 bits then apply the same normalisation to the other coefficients */
/* autoCorrelationCoefficient are normalised on 32 bits and then considered as Q31 in range [-1,1[ */
/* autoCorrelationCoefficient[0] is computed on 64 bits as it is likely to overflow 32 bits */
/* Compute autoCorrelationCoefficients[0] first as it is the highest number and normalise it on 32 bits then apply the same normalisation to the other coefficients */
/* autoCorrelationCoefficients are normalised on 32 bits and then considered as Q31 in range [-1,1[ */
/* autoCorrelationCoefficients[0] is computed on 64 bits as it is likely to overflow 32 bits */
for (i=0; i<L_LP_ANALYSIS_WINDOW; i++) {
acc64 = MAC64(acc64, windowedSignal[i], windowedSignal[i]);
}
@ -71,101 +163,51 @@ void computeLP(word16_t signal[], word16_t LPCoefficientsQ12[])
acc64 = SHR(acc64,1);
rightShiftToNormalise++;
} while (acc64>MAXINT32);
autoCorrelationCoefficient[0] = acc64;
autoCorrelationCoefficients[0] = acc64;
} else {
rightShiftToNormalise = -countLeadingZeros((word32_t)acc64);
autoCorrelationCoefficient[0] = SHL((word32_t)acc64, -rightShiftToNormalise);
autoCorrelationCoefficients[0] = SHL((word32_t)acc64, -rightShiftToNormalise);
}
/* compute autoCorrelationCoefficient 1 to 10 */
/* give current autoCorrelation coefficients scale to the output */
*autoCorrelationCoefficientsScale = -rightShiftToNormalise;
/* compute autoCorrelationCoefficients 1 to requested number (10 - no VAD - or 12 if VAD is enabled */
if (rightShiftToNormalise>0) { /* acc64 was not fitting on 32 bits so compute the other sum on 64 bits too */
for (i=1; i<NB_LSP_COEFF+1; i++) {
for (i=1; i<autoCorrelationCoefficientsNumber; i++) {
/* compute the sum in the 64 bits acc*/
acc64=0;
for (j=i; j<L_LP_ANALYSIS_WINDOW; j++) {
acc64 = ADD64_32(acc64, MULT16_16(windowedSignal[j], windowedSignal[j-i]));
}
/* normalise it */
autoCorrelationCoefficient[i] = SHR(acc64 ,rightShiftToNormalise);
autoCorrelationCoefficients[i] = SHR(acc64 ,rightShiftToNormalise);
}
} else { /* acc64 was fitting on 32 bits, compute the other sum on 32 bits only as it is faster */
for (i=1; i<NB_LSP_COEFF+1; i++) {
for (i=1; i<autoCorrelationCoefficientsNumber; i++) {
/* compute the sum in the 64 bits acc*/
word32_t acc32=0;
for (j=i; j<L_LP_ANALYSIS_WINDOW; j++) {
acc32 = MAC16_16(acc32, windowedSignal[j], windowedSignal[j-i]);
}
/* normalise it */
autoCorrelationCoefficient[i] = SHL(acc32, -rightShiftToNormalise);
autoCorrelationCoefficients[i] = SHL(acc32, -rightShiftToNormalise);
}
}
/* apply lag window on the autocorrelation coefficients spec 3.2.1 eq7 */
for (i=1; i<NB_LSP_COEFF+1; i++) {
autoCorrelationCoefficient[i] = MULT16_32_P15(wlag[i], autoCorrelationCoefficient[i]); /* wlag in Q15 */
//autoCorrelationCoefficient[i] = MULT32_32_Q31(wlag[i], autoCorrelationCoefficient[i]); /* wlag in Q31 */
/* save autocorrelation before applying lag window as they are requested like this for DTX */
for (i=0; i<autoCorrelationCoefficientsNumber; i++) {
noLagAutocorrelationCoefficients[i] = autoCorrelationCoefficients[i];
}
/*********************************************************************************/
/* Compute the LP Coefficient using Levinson-Durbin algo spec 3.2.2 */
/*********************************************************************************/
/* start a iteration i=2, init values as after iteration i=1 : */
/* a[0] = 1 */
/* a[1] = -r1/r0 */
/* E = r0(1 - a[1]^2) */
/* */
/* iterations i = 2..10 */
/* sum = r[i] + ∑ a[j]*r[i-j] with j = 1..i-1 (a[0] is always 1) */
/* a[i] = -sum/E */
/* iterations j = 1..i-1 */
/* a[j] += a[i]*a{i-1}[i-j] use a{i-1}: from previous iteration */
/* E *=(1-a[i]^2) */
/* */
/* r in Q31 (normalised) stored in array autoCorrelationCoefficient */
/* E in Q31 (can't be > 1) */
/* sum in Q27 (sum can't be > 1 but intermediate accumulation can) */
/* a in Q4.27 with full range possible */
/* Note: during iteration, current a[i] is in Q31 (can't be >1) and is */
/* set to Q27 at the end of current iteration */
/* */
/*********************************************************************************/
/* init */
LPCoefficients[0] = ONE_IN_Q27;
LPCoefficients[1] = -DIV32_32_Q27(autoCorrelationCoefficient[1], autoCorrelationCoefficient[0]); /* result in Q27(but<1) */
/* E = r0(1 - a[1]^2) in Q31 */
E = MULT32_32_Q31(autoCorrelationCoefficient[0], SUB32(ONE_IN_Q31, MULT32_32_Q23(LPCoefficients[1], LPCoefficients[1]))); /* LPCoefficient[1] is in Q27, using a Q23 operation will result in a Q31 variable */
for (i=2; i<NB_LSP_COEFF+1; i++) {
/* update the previousIterationLPCoefficients needed for this one */
for (j=1; j<i; j++) {
previousIterationLPCoefficients[j] = LPCoefficients[j];
}
/* sum = r[i] + ∑ a[j]*r[i-j] with j = 1..i-1 (a[0] is always 1) */
sum = 0;
for (j=1; j<i; j++) {
sum = MAC32_32_Q31(sum, LPCoefficients[j], autoCorrelationCoefficient[i-j]);/* LPCoefficients in Q27, autoCorrelation in Q31 -> result in Q27 -> sum in Q27 */
}
sum = ADD32(SHL(sum, 4), autoCorrelationCoefficient[i]); /* set sum in Q31 and add r[0] */
/* a[i] = -sum/E */
LPCoefficients[i] = -DIV32_32_Q31(sum,E); /* LPCoefficient of current iteration is in Q31 for now, it will be set to Q27 at the end of this iteration */
/* iterations j = 1..i-1 */
/* a[j] += a[i]*a[i-j] */
for (j=1; j<i; j++) {
LPCoefficients[j] = MAC32_32_Q31(LPCoefficients[j], LPCoefficients[i], previousIterationLPCoefficients[i-j]); /*LPCoefficients in Q27 except for LPCoefficients[i] in Q31 */
}
/* E *=(1-a[i]^2) */
E = MULT32_32_Q31(E, SUB32(ONE_IN_Q31, MULT32_32_Q31(LPCoefficients[i], LPCoefficients[i]))); /* all in Q31 */
/* set LPCoefficients[i] from Q31 to Q27 */
LPCoefficients[i] = SHR(LPCoefficients[i], 4);
/* apply lag window on the autocorrelation coefficients spec 3.2.1 eq7 */
for (i=1; i<autoCorrelationCoefficientsNumber; i++) {
autoCorrelationCoefficients[i] = MULT16_32_P15(wlag[i], autoCorrelationCoefficients[i]); /* wlag in Q15 */
//autoCorrelationCoefficients[i] = MULT32_32_Q31(wlag[i], autoCorrelationCoefficients[i]); /* wlag in Q31 */
}
/* convert with rounding the LP Coefficients form Q27 to Q12, ignore first coefficient which is always 1 */
for (i=0; i<NB_LSP_COEFF; i++) {
LPCoefficientsQ12[i] = (word16_t)SATURATE(PSHR(LPCoefficients[i+1], 15), MAXINT16);
}
/* convert to LP using Levinson-Durbin algo described in sepc 3.2.2 */
autoCorrelation2LP(autoCorrelationCoefficients, LPCoefficientsQ12, reflectionCoefficient, &residualEnergy);
return;
}

+ 49
- 0
src/computeLP.h View File

@ -0,0 +1,49 @@
/*
computeLP.h
Copyright (C) 2011 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef COMPUTELP_H
#define COMPUTELP_H
/*****************************************************************************/
/* autoCorrelation2LP: convert autocorrelation coefficients to LP using */
/* Levinson-Durbin algo described in spec 3.2.2 */
/* parameters : */
/* -(i) autoCorrelationCoefficients : 11 values in variable scale */
/* scale is not needed here as a division cancel it */
/* -(o) LPCoefficientsQ12: 10 LP coefficients in Q12 */
/* -(o) reflectionCoefficient: in Q31, k[1] generated during Levinson */
/* Durbin LP coefficient generation and needed for VAD */
/* -(o) residualEnergy : with the same scale factor as input */
/* autoCorrelationCoefficients, needed by DTX */
/* */
/*****************************************************************************/
void autoCorrelation2LP(word32_t autoCorrelationCoefficients[], word16_t LPCoefficientsQ12[], word32_t *reflectionCoefficient, word32_t *residualEnergy);
/*****************************************************************************/
/* computeLP : As described in spec 3.2.1 and 3.2.2 : Windowing, */
/* Autocorrelation and Levinson-Durbin algorithm */
/* parameters: */
/* -(i) signal: 240 samples in Q0, the last 40 are from next frame */
/* -(o) LPCoefficientsQ12: 10 LP coefficients in Q12 */
/* -(o) reflectionCoefficient: in Q31, k[1] generated during Levinson */
/* Durbin LP coefficient generation and needed for VAD */
/* */
/*****************************************************************************/
void computeLP(word16_t signal[], word16_t LPCoefficientsQ12[], word32_t *reflectionCoefficient, word32_t autoCorrelationCoefficients[], word32_t noLagAutocorrelationCoefficients[], int8_t *autoCorrelationCoefficientsScale, uint8_t autoCorrelationCoefficientsNumber);
#endif /* ifndef COMPUTELP_H */

include/computeWeightedSpeech.h → src/computeWeightedSpeech.h View File


+ 50
- 34
src/decodeAdaptativeCodeVector.c View File

@ -33,6 +33,53 @@ void initDecodeAdaptativeCodeVector(bcg729DecoderChannelContextStruct *decoderCh
}
/*****************************************************************************/
/* computeAdaptativeCodeVector : as in spec 4.1.3 */
/* parameters: */
/* -(i/o) excitationVector : in Q0 excitation accessed from */
/* [-MAXIMUM_INT_PITCH_DELAY(143), -1] as input */
/* and [0, L_SUBFRAME[ as output to store the adaptative */
/* codebook vector */
/* -(i/o) fracPitchDelay : the fractionnal part of Pitch Delay. */
/* -(i/o) intPitchDelay : the integer part of Pitch Delay. */
/* */
/*****************************************************************************/
void computeAdaptativeCodebookVector(word16_t *excitationVector, int16_t fracPitchDelay, int16_t intPitchDelay) {
word16_t *excitationVectorMinusK; /* pointer to u(-k) */
int n;
/* compute the adaptative codebook vector using the pitch delay and the past excitation vector */
/* from spec 4.1.3 and 3.7.1 */
/* shall compute v(n ) = ∑ u (n - k + i )b30 (t + 3i ) + ∑ u (n - k + 1 + i )b30 (3 - t + 3i ) for i=0,...,9 and n = 0,...,39 (t in 0, 1, 2) */
/* with k = intPitchDelay and t = fracPitchDelay wich must be converted from range -1,0,1 to 0,1,2 */
/* u the past excitation vector */
/* v the adaptative codebook vector */
/* b30 an interpolation filter */
/* scale fracPichDelay from -1,0.1 to 0,1,2 */
if (fracPitchDelay==1) {
excitationVectorMinusK = &(excitationVector[-(intPitchDelay+1)]); /* fracPitchDelay being positive -> increase by one the integer part and set to 2 the fractional part : -(k+1/3) -> -(k+1)+2/3 */
fracPitchDelay = 2;
} else {
fracPitchDelay = -fracPitchDelay; /* 0 unchanged, -1 -> +1 */
excitationVectorMinusK = &(excitationVector[-intPitchDelay]); /* -(k-1/3) -> -k+1/3 or -(k) -> -k*/
}
for (n=0; n<L_SUBFRAME; n++) { /* loop over the whole subframe */
word16_t *excitationVectorNMinusK = &(excitationVectorMinusK[n]); /* point to u(n-k), unscaled value, full range */
word16_t *excitationVectorNMinusKPlusOne = &(excitationVectorMinusK[n+1]); /* point to u(n-k+1), unscaled value, full range */
word16_t *b301 = &(b30[fracPitchDelay]); /* point to b30(t) in Q0.15 : sums of all b30 coeffs is < 2, no overflow possible on 32 bits */
word16_t *b302 = &(b30[3-fracPitchDelay]); /* point to b30(3-t) in Q0.15*/
int i,j; /* j will store 3i */
word32_t acc = 0; /* in Q15 */
for (i=0, j=0; i<10; i++, j+=3) {
acc = MAC16_16(acc, excitationVectorNMinusK[-i], b301[j]); /* Note : the spec says: u(n−k+i)b30(t+3i) but the ITU code do (and here too) u(n-k-i )b30(t+3i) */
acc = MAC16_16(acc, excitationVectorNMinusKPlusOne[i], b302[j]); /* u(n-k+1+i)b30(3-t+3i) */
}
excitationVector[n] = SATURATE(PSHR(acc, 15), MAXINT16); /* acc in Q15, shift/round to unscaled value and check overflow on 16 bits */
}
}
/*****************************************************************************/
/* decodeAdaptativeCodeVector : as in spec 4.1.3 */
@ -55,8 +102,6 @@ void decodeAdaptativeCodeVector(bcg729DecoderChannelContextStruct *decoderChanne
int16_t *intPitchDelay, word16_t *excitationVector)
{
int16_t fracPitchDelay;
word16_t *excitationVectorMinusK; /* pointer to u(-k) */
int n;
/*** Compute the Pitch Delay from the Codebook index ***/
/* fracPitchDelay is computed in the range -1,0,1 */
@ -108,38 +153,9 @@ void decodeAdaptativeCodeVector(bcg729DecoderChannelContextStruct *decoderChanne
}
}
/* compute the adaptative codebook vector using the pitch delay we just get and the past excitation vector */
computeAdaptativeCodebookVector(excitationVector, fracPitchDelay, *intPitchDelay);
/* now compute the adaptative codebook vector using the pitch delay we just get and the past excitation vector */
/* from spec 4.1.3 and 3.7.1 */
/* shall compute v(n ) = ∑ u (n - k + i )b30 (t + 3i ) + ∑ u (n - k + 1 + i )b30 (3 - t + 3i ) for i=0,...,9 and n = 0,...,39 (t in 0, 1, 2) */
/* with k = intPitchDelay and t = fracPitchDelay wich must be converted from range -1,0,1 to 0,1,2 */
/* u the past excitation vector */
/* v the adaptative codebook vector */
/* b30 an interpolation filter */
/* scale fracPichDelay from -1,0.1 to 0,1,2 */
if (fracPitchDelay==1) {
excitationVectorMinusK = &(excitationVector[-(*intPitchDelay+1)]); /* fracPitchDelay being positive -> increase by one the integer part and set to 2 the fractional part : -(k+1/3) -> -(k+1)+2/3 */
fracPitchDelay = 2;
} else {
fracPitchDelay = -fracPitchDelay; /* 0 unchanged, -1 -> +1 */
excitationVectorMinusK = &(excitationVector[-(*intPitchDelay)]); /* -(k-1/3) -> -k+1/3 or -(k) -> -k*/
}
for (n=0; n<L_SUBFRAME; n++) { /* loop over the whole subframe */
word16_t *excitationVectorNMinusK = &(excitationVectorMinusK[n]); /* point to u(n-k), unscaled value, full range */
word16_t *excitationVectorNMinusKPlusOne = &(excitationVectorMinusK[n+1]); /* point to u(n-k+1), unscaled value, full range */
word16_t *b301 = &(b30[fracPitchDelay]); /* point to b30(t) in Q0.15 : sums of all b30 coeffs is < 2, no overflow possible on 32 bits */
word16_t *b302 = &(b30[3-fracPitchDelay]); /* point to b30(3-t) in Q0.15*/
int i,j; /* j will store 3i */
word32_t acc = 0; /* in Q15 */
for (i=0, j=0; i<10; i++, j+=3) {
acc = MAC16_16(acc, excitationVectorNMinusK[-i], b301[j]); /* Note : the spec says: u(n−k+i)b30(t+3i) but the ITU code do (and here too) u(n-k-i )b30(t+3i) */
acc = MAC16_16(acc, excitationVectorNMinusKPlusOne[i], b302[j]); /* u(n-k+1+i)b30(3-t+3i) */
}
excitationVector[n] = SATURATE(PSHR(acc, 15), MAXINT16); /* acc in Q15, shift/round to unscaled value and check overflow on 16 bits */
}
return;
}

include/decodeAdaptativeCodeVector.h → src/decodeAdaptativeCodeVector.h View File


include/decodeFixedCodeVector.h → src/decodeFixedCodeVector.h View File


include/decodeGains.h → src/decodeGains.h View File


+ 65
- 46
src/decodeLSP.c View File

@ -48,6 +48,70 @@ void initDecodeLSP(bcg729DecoderChannelContextStruct *decoderChannelContext)
}
}
//[MA_MAX_K][NB_LSP_COEFF]; /* in Q2.13, buffer to store the last 4 frames codewords, used to compute the current qLSF */
/*****************************************************************************/
/* computeqLSF : get qLSF extracted from codebooks and process them */
/* according to spec 3.2.4 */
/* parameters: */
/* -(i/o) codebookqLSF : 10 values i Q2.13 to be updated */
/* -(i/o) previousCodeWord : codewords for the last 4 subframes in Q2.13*/
/* is updated by this function */
/* -(i) L0: the Switched MA predictor retrieved from bitstream */
/* */
/*****************************************************************************/
void computeqLSF(word16_t *codebookqLSF, word16_t previousLCodeWord[MA_MAX_K][NB_LSP_COEFF], uint8_t L0, word16_t currentMAPredictor[L0_RANGE][MA_MAX_K][NB_LSP_COEFF], word16_t currentMAPredictorSum[L0_RANGE][NB_LSP_COEFF]) {
int i,j;
word32_t acc; /* Accumulator in Q2.28 */
/*** rearrange in order to have a minimum distance between two consecutives coefficients ***/
rearrangeCoefficients(codebookqLSF, GAP1);
rearrangeCoefficients(codebookqLSF, GAP2); /* codebookqLSF still in Q2.13 */
/*** doc 3.2.4 eq(20) ***/
/* compute the qLSF as a weighted sum(weighted by MA coefficient selected according to L0 value) of previous and current frame L codewords coefficients */
/* L0 is the Switched MA predictor of LSP quantizer(1 bit) */
/* codebookqLSF and previousLCodeWord in Q2.13 */
/* MAPredictor and MAPredictorSum in Q0.15 with MAPredictorSum[MA switch][i]+Sum[j=0-3](MAPredictor[MA switch][j][i])=1 -> acc will end up being in Q2.28*/
/* Note : previousLCodeWord array containing the last 4 code words is updated during this phase */
for (i=0; i<NB_LSP_COEFF; i++) {
acc = MULT16_16(currentMAPredictorSum[L0][i], codebookqLSF[i]);
for (j=MA_MAX_K-1; j>=0; j--) {
acc = MAC16_16(acc, currentMAPredictor[L0][j][i], previousLCodeWord[j][i]);
previousLCodeWord[j][i] = (j>0)?previousLCodeWord[j-1][i]:codebookqLSF[i]; /* update the previousqLCodeWord array: row[0] = current code word and row[j]=row[j-1] */
}
/* acc in Q2.28, shift back the acc to a Q2.13 with rounding */
codebookqLSF[i] = (word16_t)PSHR(acc, 15); /* codebookqLSF in Q2.13 */
}
/* Note : codebookqLSF buffer now contains qLSF */
/*** doc 3.2.4 qLSF stability ***/
/* qLSF in Q2.13 as are qLSF_MIN and qLSF_MAX and MIN_qLSF_DISTANCE */
/* sort the codebookqLSF array */
insertionSort(codebookqLSF, NB_LSP_COEFF);
/* check for low limit on qLSF[0] */
if (codebookqLSF[1]<qLSF_MIN) {
codebookqLSF[1] = qLSF_MIN;
}
/* check and rectify minimum distance between two consecutive qLSF */
for (i=0; i<NB_LSP_COEFF-1; i++) {
if (SUB16(codebookqLSF[i+1],codebookqLSF[i])<MIN_qLSF_DISTANCE) {
codebookqLSF[i+1] = codebookqLSF[i]+MIN_qLSF_DISTANCE;
}
}
/* check for upper limit on qLSF[NB_LSP_COEFF-1] */
if (codebookqLSF[NB_LSP_COEFF-1]>qLSF_MAX) {
codebookqLSF[NB_LSP_COEFF-1] = qLSF_MAX;
}
}
/*****************************************************************************/
/* decodeLSP : decode LSP coefficients as in spec 4.1.1/3.2.4 */
/* parameters: */
@ -65,7 +129,6 @@ void decodeLSP(bcg729DecoderChannelContextStruct *decoderChannelContext, uint16_
if (frameErased == 0) { /* frame is ok, proceed according to 3.2.4 section of the doc */
word32_t acc; /* Accumulator in Q2.28 */
/*** doc 3.2.4 eq(19) ***/
/* get the L codewords from the codebooks L1, L2 and L3 */
@ -81,51 +144,7 @@ void decodeLSP(bcg729DecoderChannelContextStruct *decoderChannelContext, uint16_
currentqLSF[i] = ADD16(L1[L[1]][i], L2L3[L[3]][i]); /* same as previous, output in Q2.13 */
}
/*** rearrange in order to have a minimum distance between two consecutives coefficients ***/
rearrangeCoefficients(currentqLSF, GAP1);
rearrangeCoefficients(currentqLSF, GAP2); /* currentqLSF still in Q2.13 */
/*** doc 3.2.4 eq(20) ***/
/* compute the qLSF as a weighted sum(weighted by MA coefficient selected according to L0 value) of previous and current frame L codewords coefficients */
/* L[0] is the Switched MA predictor of LSP quantizer(1 bit) */
/* currentqLSF and previousLCodeWord in Q2.13 */
/* MAPredictor and MAPredictorSum in Q0.15 with MAPredictorSum[MA switch][i]+Sum[j=0-3](MAPredictor[MA switch][j][i])=1 -> acc will end up being in Q2.28*/
/* Note : previousLCodeWord array containing the last 4 code words is updated during this phase */
for (i=0; i<NB_LSP_COEFF; i++) {
acc = MULT16_16(MAPredictorSum[L[0]][i], currentqLSF[i]);
for (j=MA_MAX_K-1; j>=0; j--) {
acc = MAC16_16(acc, MAPredictor[L[0]][j][i], decoderChannelContext->previousLCodeWord[j][i]);
decoderChannelContext->previousLCodeWord[j][i] = (j>0)?decoderChannelContext->previousLCodeWord[j-1][i]:currentqLSF[i]; /* update the previousqLCodeWord array: row[0] = current code word and row[j]=row[j-1] */
}
/* acc in Q2.28, shift back the acc to a Q2.13 with rounding */
currentqLSF[i] = (word16_t)PSHR(acc, 15); /* currentqLSF in Q2.13 */
}
/* Note : currentqLSF buffer now contains qLSF */
/*** doc 3.2.4 qLSF stability ***/
/* qLSF in Q2.13 as are qLSF_MIN and qLSF_MAX and MIN_qLSF_DISTANCE */
/* sort the currentqLSF array */
insertionSort(currentqLSF, NB_LSP_COEFF);
/* check for low limit on qLSF[0] */
if (currentqLSF[1]<qLSF_MIN) {
currentqLSF[1] = qLSF_MIN;
}
/* check and rectify minimum distance between two consecutive qLSF */
for (i=0; i<NB_LSP_COEFF-1; i++) {
if (SUB16(currentqLSF[i+1],currentqLSF[i])<MIN_qLSF_DISTANCE) {
currentqLSF[i+1] = currentqLSF[i]+MIN_qLSF_DISTANCE;
}
}
/* check for upper limit on qLSF[NB_LSP_COEFF-1] */
if (currentqLSF[NB_LSP_COEFF-1]>qLSF_MAX) {
currentqLSF[NB_LSP_COEFF-1] = qLSF_MAX;
}
computeqLSF(currentqLSF, decoderChannelContext->previousLCodeWord, L[0], MAPredictor, MAPredictorSum); /* use regular MAPredictor as this function is not called on SID frame decoding */
/* backup the qLSF and L0 to restore them in case of frame erased */
for (i=0; i<NB_LSP_COEFF; i++) {


include/decodeLSP.h → src/decodeLSP.h View File


+ 79
- 25
src/decoder.c View File

@ -36,13 +36,13 @@
#include "LPSynthesisFilter.h"
#include "postFilter.h"
#include "postProcessing.h"
#include "cng.h"
#include "stdio.h"
/* buffers allocation */
static const word16_t previousqLSPInitialValues[NB_LSP_COEFF] = {30000, 26000, 21000, 15000, 8000, 0, -8000,-15000,-21000,-26000}; /* in Q0.15 the initials values for the previous qLSP buffer */
/* internal functions */
uint16_t pseudoRandom(bcg729DecoderChannelContextStruct *decoderChannelContext);
/*****************************************************************************/
/* initBcg729DecoderChannel : create context structure and initialise it */
/* return value : */
@ -53,15 +53,20 @@ bcg729DecoderChannelContextStruct *initBcg729DecoderChannel()
{
/* create the context structure */
bcg729DecoderChannelContextStruct *decoderChannelContext = malloc(sizeof(bcg729DecoderChannelContextStruct));
memset(decoderChannelContext, 0, sizeof(bcg729DecoderChannelContextStruct));
/* intialise statics buffers and variables */
memcpy(decoderChannelContext->previousqLSP, previousqLSPInitialValues, NB_LSP_COEFF*sizeof(word16_t)); /* initialise the previousqLSP buffer */
memset(decoderChannelContext->excitationVector, 0, L_PAST_EXCITATION*sizeof(word16_t)); /* initialise the part of the excitationVector containing the past excitation */
decoderChannelContext->boundedAdaptativeCodebookGain = BOUNDED_PITCH_GAIN_MIN;
decoderChannelContext->pseudoRandomSeed = 21845; /* initialise pseudo Random seed according to spec 4.4.4 */
decoderChannelContext->CNGpseudoRandomSeed = CNG_DTX_RANDOM_SEED_INIT; /* initialise CNG pseudo Random seed according to ITU code */
decoderChannelContext->adaptativeCodebookGain = 0; /* gains are initialised at 0 */
decoderChannelContext->fixedCodebookGain = 0;
memset(decoderChannelContext->reconstructedSpeech, 0, NB_LSP_COEFF*sizeof(word16_t)); /* initialise to zero all the values used from previous frame to get the current frame reconstructed speech */
decoderChannelContext->previousFrameIsActiveFlag = 1;
decoderChannelContext->CNGChannelContext = initBcg729CNGChannel();
/* initialisation of the differents blocs which need to be initialised */
initDecodeLSP(decoderChannelContext);
@ -81,7 +86,12 @@ bcg729DecoderChannelContextStruct *initBcg729DecoderChannel()
/*****************************************************************************/
void closeBcg729DecoderChannel(bcg729DecoderChannelContextStruct *decoderChannelContext)
{
free(decoderChannelContext);
if (decoderChannelContext) {
if (decoderChannelContext->CNGChannelContext) {
free(decoderChannelContext->CNGChannelContext);
}
free(decoderChannelContext);
}
return;
}
@ -91,14 +101,14 @@ void closeBcg729DecoderChannel(bcg729DecoderChannelContextStruct *decoderChannel
/* -(i) decoderChannelContext : the channel context data */
/* -(i) bitStream : 15 parameters on 80 bits */
/* -(i) frameErased: flag: true, frame has been erased */
/* -(i) SIDFrameFlag: flag: true, frame is a SID one */
/* -(o) signal : a decoded frame 80 samples (16 bits PCM) */
/* */
/*****************************************************************************/
void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uint8_t bitStream[], uint8_t frameErasureFlag, int16_t signal[])
void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uint8_t bitStream[], uint8_t frameErasureFlag, uint8_t SIDFrameFlag, int16_t signal[])
{
int i;
uint16_t parameters[NB_PARAMETERS];
/* internal buffers which we do not need to keep between calls */
word16_t qLSP[NB_LSP_COEFF]; /* store the qLSP coefficients in Q0.15 */
word16_t interpolatedqLSP[NB_LSP_COEFF]; /* store the interpolated qLSP coefficient in Q0.15 */
@ -129,14 +139,74 @@ void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uin
/* 12 -> S2 (4 bits) */
/* 13 -> GA2(3 bits) */
/* 14 -> GB2(4 bits) */
/* in case of SID frame : params are decoded in the decodeSIDframe functions */
/* 0-> L0 (1 bit) */
/* 1-> L1 (5 bits) */
/* 2-> L2 (4 bits) */
/* 3-> Gain (5 bits) */
if (bitStream!=NULL) { /* bitStream might be null in case of frameErased (which shall be set in the appropriated flag)*/
parametersBitStream2Array(bitStream, parameters);
if (SIDFrameFlag == 0) {
parametersBitStream2Array(bitStream, parameters);
}
} else { /* avoid compiler complaining for non inizialazed use of variable */
for (i=0; i<NB_PARAMETERS; i++) {
parameters[i]=0;
}
}
/* manage frameErasure and CNG as specified in B.27 */
if (frameErasureFlag) {
if (decoderChannelContext->previousFrameIsActiveFlag) {
SIDFrameFlag = 0;
} else {
SIDFrameFlag = 1;
}
}
/* this is a SID frame, process it using the dedicated function */
if (SIDFrameFlag == 1) {
decodeSIDframe(decoderChannelContext->CNGChannelContext, decoderChannelContext->previousFrameIsActiveFlag, bitStream, &(decoderChannelContext->excitationVector[L_PAST_EXCITATION]), decoderChannelContext->previousqLSP, LP, &(decoderChannelContext->CNGpseudoRandomSeed), decoderChannelContext->previousLCodeWord);
decoderChannelContext->previousFrameIsActiveFlag = 0;
/* loop over the two subframes */
for (subframeIndex=0; subframeIndex<L_FRAME; subframeIndex+=L_SUBFRAME) {
/* reconstruct speech using LP synthesis filter spec 4.1.6 eq77 */
/* excitationVector in Q0, LP in Q12, recontructedSpeech in Q0 -> +NB_LSP_COEFF on the index of this one because the first NB_LSP_COEFF elements store the previous frame filter output */
LPSynthesisFilter(&(decoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex]), &(LP[LPCoefficientsIndex]), &(decoderChannelContext->reconstructedSpeech[NB_LSP_COEFF+subframeIndex]) );
/* NOTE: ITU code check for overflow after LP Synthesis Filter computation and if it happened, divide excitation buffer by 2 and recompute the LP Synthesis Filter */
/* here, possible overflows are managed directly inside the Filter by saturation at MAXINT16 on each result */
/* postFilter */
postFilter(decoderChannelContext, &(LP[LPCoefficientsIndex]), /* select the LP coefficients for this subframe, use last frame intPitchDelay */
&(decoderChannelContext->reconstructedSpeech[NB_LSP_COEFF+subframeIndex]), decoderChannelContext->previousIntPitchDelay, subframeIndex, postFilteredSignal);
/* postProcessing */
postProcessing(decoderChannelContext, postFilteredSignal);
/* copy postProcessing Output to the signal output buffer */
for (i=0; i<L_SUBFRAME; i++) {
signal[subframeIndex+i] = postFilteredSignal[i];
}
/* increase LPCoefficient Indexes */
LPCoefficientsIndex+=NB_LSP_COEFF;
}
decoderChannelContext->boundedAdaptativeCodebookGain = BOUNDED_PITCH_GAIN_MIN;
/* Shift Excitation Vector by L_FRAME left */
memmove(decoderChannelContext->excitationVector, &(decoderChannelContext->excitationVector[L_FRAME]), L_PAST_EXCITATION*sizeof(word16_t));
/* Copy the last 10 words of reconstructed Speech to the begining of the array for next frame computation */
memcpy(decoderChannelContext->reconstructedSpeech, &(decoderChannelContext->reconstructedSpeech[L_FRAME]), NB_LSP_COEFF*sizeof(word16_t));
return;
}
decoderChannelContext->previousFrameIsActiveFlag = 1;
/* re-init the CNG pseudo random seed at each active frame spec B.4 */
decoderChannelContext->CNGpseudoRandomSeed = CNG_DTX_RANDOM_SEED_INIT; /* re-initialise CNG pseudo Random seed to 11111 according to ITU code */
/*****************************************************************************************/
/*** on frame basis : decodeLSP, interpolate them with previous ones and convert to LP ***/
@ -176,8 +246,8 @@ void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uin
/* in case of frame erasure we shall generate pseudoRandom signs and index for fixed code vector decoding according to spec 4.4.4 */
if (frameErasureFlag) {
parameters[parametersIndex] = pseudoRandom(decoderChannelContext)&(uint16_t)0x1fff; /* signs are set to the 13 LSB of the first pseudoRandom number */
parameters[parametersIndex+1] = pseudoRandom(decoderChannelContext)&(uint16_t)0x000f; /* signs are set to the 4 LSB of the second pseudoRandom number */
parameters[parametersIndex] = pseudoRandom(&(decoderChannelContext->pseudoRandomSeed))&(uint16_t)0x1fff; /* signs are set to the 13 LSB of the first pseudoRandom number */
parameters[parametersIndex+1] = pseudoRandom(&(decoderChannelContext->pseudoRandomSeed))&(uint16_t)0x000f; /* signs are set to the 4 LSB of the second pseudoRandom number */
}
/* decode the fixed Code Vector */
@ -241,19 +311,3 @@ void bcg729Decoder(bcg729DecoderChannelContextStruct *decoderChannelContext, uin
return;
}
/*****************************************************************************/
/* pseudoRandom : generate pseudo random number as in spec 4.4.4 eq96 */
/* parameters: */
/* -(i) decoderChannelContext : the channel context data */
/* return value : */
/* - a unsigned 16 bits pseudo random number */
/* */
/*****************************************************************************/
uint16_t pseudoRandom(bcg729DecoderChannelContextStruct *decoderChannelContext)
{
/* pseudoRandomSeed is stored in an uint16_t var, we shall not worry about overflow here */
/* pseudoRandomSeed*31821 + 13849; */
return decoderChannelContext->pseudoRandomSeed = MAC16_16(13849, (decoderChannelContext->pseudoRandomSeed), 31821);
}

+ 431
- 0
src/dtx.c View File

@ -0,0 +1,431 @@
/*
dtx.c
Comfort Noise Generation
Copyright (C) 2015 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include "typedef.h"
#include "codecParameters.h"
#include "basicOperationsMacros.h"
#include "utils.h"
#include "dtx.h"
#include "computeLP.h"
#include "g729FixedPointMath.h"
#include "LP2LSPConversion.h"
#include "LSPQuantization.h"
#include "codebooks.h"
#include "cng.h"
#include "interpolateqLSP.h"
#include "qLSP2LP.h"
#define SID_FRAME 2
#define UNTRANSMITTED_FRAME 0
/*** local functions ***/
static void sumAutocorrelationCoefficients(word32_t autoCorrelationCoefficients[][NB_LSP_COEFF+1], int8_t *autocorrelationCoefficientsScale, uint8_t nbElements,
word32_t *autoCorrelationCoefficientsResult, int8_t *autocorrelationCoefficientsScaleResults) {
int i,j;
word64_t autoCorrelationSumBuffer[NB_LSP_COEFF+1]; /* used to temporary store sum on 64 bits */
word64_t max=0;
word32_t rescaledAutocorrelationCoefficients[7][NB_LSP_COEFF+1]; /* used to temporary stored rescaled elements */
int8_t rightShiftToNormalise = 0;
/* get lowest scale */
int8_t minScale = autocorrelationCoefficientsScale[0];
for (i=1; i<nbElements; i++) {
if (autocorrelationCoefficientsScale[i]<minScale) {
minScale=autocorrelationCoefficientsScale[i];
}
}
/* rescale the coefficients */
for (j=0; j<nbElements; j++) {
int8_t rescaling = autocorrelationCoefficientsScale[j] - minScale;
for (i=0; i<NB_LSP_COEFF+1; i++) {
rescaledAutocorrelationCoefficients[j][i] = SHR32(autoCorrelationCoefficients[j][i], rescaling);
}
}
/* sum them on 64 bits and get the maximum value reached */
for (i=0; i<NB_LSP_COEFF+1; i++) {
autoCorrelationSumBuffer[i] = rescaledAutocorrelationCoefficients[0][i];
for (j=1; j<nbElements; j++) {
autoCorrelationSumBuffer[i] = ADD64(autoCorrelationSumBuffer[i], rescaledAutocorrelationCoefficients[j][i]);
}
if (ABS(autoCorrelationSumBuffer[i])>max) max = ABS(autoCorrelationSumBuffer[i]);
}
/* normalise result on 32 bits */
if (max>MAXINT32) {
do {
max = SHR(max,1);
rightShiftToNormalise++;
} while (max>MAXINT32);
for (i=0; i<NB_LSP_COEFF+1; i++) {
autoCorrelationCoefficientsResult[i] = (word32_t)SHR64(autoCorrelationSumBuffer[i], rightShiftToNormalise);
}
} else {
for (i=0; i<NB_LSP_COEFF+1; i++) {
autoCorrelationCoefficientsResult[i] = (word32_t)(autoCorrelationSumBuffer[i]);
}
}
/* adjust output scale according to possible right shift */
*autocorrelationCoefficientsScaleResults = minScale - rightShiftToNormalise;
return;
}
/*****************************************************************************/
/* residual Energy quantization according to spec B4.2.1 */
/* parameters: */
/* -(i) residualEnergy : to be quantized in variable scale */
/* -(i) residualEnergyScale : scale of previous parameter */
/* -(o) decodedLogEnergy : decode the quantized energy into a 10Log(E) */
/* returns the quantized residual energy parameterR(on 5 bits) */
/* */
/*****************************************************************************/
static uint8_t residualEnergyQuantization(word32_t residualEnergy, int8_t residualEnergyScale, int8_t *decodedLogEnergy) {
word32_t acc;
//acc = SUB32(g729Log2_Q0Q16(residualEnergy), ADD32(676458, (int32_t)(residualEnergyScale<<16))); /* -676458 is log2(aw/(NCur*80)) acc is log2(E') in Q16 aw=0.125*/
//acc = SUB32(g729Log2_Q0Q16(residualEnergy), ADD32(610922, (int32_t)(residualEnergyScale<<16))); /* -676458 is log2(aw/(NCur*80)) acc is log2(E') in Q16 aw=0.25*/
acc = SUB32(g729Log2_Q0Q16(residualEnergy), ADD32(479849, (int32_t)(residualEnergyScale<<16))); /* -479849 is log2(aw/(NCur*80)) acc is log2(E') in Q16 aw = 1 */
acc = SHR32(acc,1); /* acc = log2(E') in Q15 */
acc = MULT16_32_Q15(INV_LOG2_10_Q15, acc); /* acc log10(E') in Q15 */
/* quantization acc contains value to be quantized/10 so all constant / 10 respect what is in the spec */
if (acc < - 26214) { /* -0.8 in Q15 */
*decodedLogEnergy = -12;
return 0; /* first step by 8 */
} else if (acc < 45875 ) { /* 1,4 in Q15 */
uint8_t steps;
acc = (acc+19661); /* up to 14, step by 0.4*/
if (acc<0) {
acc= 0;
} else {
acc = MULT16_32_Q13(20480, acc); /* step by 0.4, 20480 is 1/0.4 in Q13 -> acc still in Q15 */
}
steps = SHR(acc,15);
*decodedLogEnergy = -2 +4*steps;
return 1+steps;
} else if (acc<216268) { /* check that log(E') is not > 66dB (216268 is 6.6 in Q15) */
uint8_t steps;
acc = (acc-49152); /* -1.5 in Q15 */
if (acc<0) {
acc = 0;
} else {
acc = MULT16_32_Q12(20480, acc); /* step by 0.2, 20480 is 1/0.2 in Q12 -> acc still in Q15 */
}
steps = SHR(acc,15);
*decodedLogEnergy = 16 +2*steps;
return 6+steps;
} else { /* quantized energy support up to 66dB */
*decodedLogEnergy = 66;
return 32;
}
}
/*****************************************************************************/
/* compute LP Coefficients auto correlation as in eq B.13 */
/* parameters: */
/* -(i) LPCoefficients : in Q12, 10 values, 1 LP Coeff is always 1 and not*/
/* stored in this buffer */
/* -(o) LPCautocorrelation : 11 values in Q20 */
/* */
/*****************************************************************************/
static void computeLPCoefficientAutocorrelation(word16_t *LPCoefficients, word32_t *LPCautocorrelation) {
int j,k;
/* first compute Ra0 */
LPCautocorrelation[0] = 4096*4096>>4; /* LPCoefficients are in Q12 -> acc in Q24, init: acc = LP(0)*LP(0) -> 1 in Q20 as LP(0) is not stored because always 1 */
for (k=0; k<NB_LSP_COEFF; k++) {
LPCautocorrelation[0] = MAC16_16_Q4(LPCautocorrelation[0], LPCoefficients[k], LPCoefficients[k]); /* LPCoefficients in Q12*Q12 -> Q24 >> Q4: result in Q20 */
}
/* and the rest */
for (j=1; j<NB_LSP_COEFF+1; j++) {
LPCautocorrelation[j] = SHL(LPCoefficients[j-1],9); /* LPCoeff[0] is not stored always 1, so LPCoeff index is -1 respect LPCautocorrelation, SHL(9) to make *2 and get it in Q20 from Q12 */
for (k=0; k<10-j; k++) {
LPCautocorrelation[j] = MAC16_16_Q3(LPCautocorrelation[j], LPCoefficients[k], LPCoefficients[k+j]); /* this k is actually k-1 respect to eq B.13 Q12*Q12 -> Q24 >> 3 : *2 and result in Q20 */
}
}
}
/********************************************************************************/
/* compare LPC filters: as in spec B.4.1.3 eq B.12 */
/* parameters: */
/* -(i) LPCoefficientsAutocorrelation: 11 values in Q20, Ra in spec */
/* -(i) autocorrelationCoefficients: 11 values in variable scale, Rt in spec */
/* -(i) residualEnergy : in the same scale as previous value, Et in spec */
/* -(i) threshold : in Q20 */
/* return 1 if the filter significantly differs (eq B.12 is true) */
/* */
/********************************************************************************/
static uint8_t compareLPCFilters(word32_t *LPCoefficientsAutocorrelation, word32_t *autocorrelationCoefficients, word32_t residualEnergy, word32_t threshold) {
/* on the left term of the comparison we have Ra in Q20 an Rt in variable scale */
/* on the right term of the comparison we have Threshold in Q20 an Et in variable scale but same as Rt */
word64_t acc = 0;
int i;
for (i=0; i<NB_LSP_COEFF+1; i++) {
acc = MAC64(acc, LPCoefficientsAutocorrelation[i], autocorrelationCoefficients[i]);
}
if (acc >= MULT32_32(residualEnergy, threshold)) {
return 1;
} else {
return 0;
}
}
/*****************************************************************************/
/* initBcg729DTXChannel : create context structure and initialise it */
/* return value : */
/* - the DTX channel context data */
/* */
/*****************************************************************************/
bcg729DTXChannelContextStruct *initBcg729DTXChannel() {
/* create the context structure */
bcg729DTXChannelContextStruct *DTXChannelContext = malloc(sizeof(bcg729DTXChannelContextStruct));
memset(DTXChannelContext, 0, sizeof(*DTXChannelContext)); /* set autocorrelation buffers to 0 */
DTXChannelContext->previousVADflag = 1; /* previous VAD flag must be initialised to VOICE */
DTXChannelContext->pseudoRandomSeed = CNG_DTX_RANDOM_SEED_INIT;
return DTXChannelContext;
}
/*******************************************************************************************/
/* updateDTXContext : save autocorrelation value in DTX context as requested in B4.1.1 */
/* parameters: */
/* -(i/o) DTXChannelContext : the DTX context to be updated */
/* -(i) autocorrelationsCoefficients : 11 values of variable scale, values are copied */
/* in DTX context */
/* -(i) autocorrelationCoefficientsScale : the scale of previous buffer(can be <0) */
/* */
/*******************************************************************************************/
void updateDTXContext(bcg729DTXChannelContextStruct *DTXChannelContext, word32_t *autocorrelationCoefficients, int8_t autocorrelationCoefficientsScale) {
/* move previous autocorrelation coefficients and store the new one */
/* TODO: optimise it buy using rolling index */
memcpy(DTXChannelContext->autocorrelationCoefficients[6], DTXChannelContext->autocorrelationCoefficients[5], (NB_LSP_COEFF+1)*sizeof(word32_t));
DTXChannelContext->autocorrelationCoefficientsScale[6] = DTXChannelContext->autocorrelationCoefficientsScale[5];
memcpy(DTXChannelContext->autocorrelationCoefficients[5], DTXChannelContext->autocorrelationCoefficients[4], (NB_LSP_COEFF+1)*sizeof(word32_t));
DTXChannelContext->autocorrelationCoefficientsScale[5] = DTXChannelContext->autocorrelationCoefficientsScale[4];
memcpy(DTXChannelContext->autocorrelationCoefficients[4], DTXChannelContext->autocorrelationCoefficients[3], (NB_LSP_COEFF+1)*sizeof(word32_t));
DTXChannelContext->autocorrelationCoefficientsScale[4] = DTXChannelContext->autocorrelationCoefficientsScale[3];
memcpy(DTXChannelContext->autocorrelationCoefficients[3], DTXChannelContext->autocorrelationCoefficients[2], (NB_LSP_COEFF+1)*sizeof(word32_t));
DTXChannelContext->autocorrelationCoefficientsScale[3] = DTXChannelContext->autocorrelationCoefficientsScale[2];
memcpy(DTXChannelContext->autocorrelationCoefficients[2], DTXChannelContext->autocorrelationCoefficients[1], (NB_LSP_COEFF+1)*sizeof(word32_t));
DTXChannelContext->autocorrelationCoefficientsScale[2] = DTXChannelContext->autocorrelationCoefficientsScale[1];
memcpy(DTXChannelContext->autocorrelationCoefficients[1], DTXChannelContext->autocorrelationCoefficients[0], (NB_LSP_COEFF+1)*sizeof(word32_t));
DTXChannelContext->autocorrelationCoefficientsScale[1] = DTXChannelContext->autocorrelationCoefficientsScale[0];
memcpy(DTXChannelContext->autocorrelationCoefficients[0], autocorrelationCoefficients, (NB_LSP_COEFF+1)*sizeof(word32_t));
DTXChannelContext->autocorrelationCoefficientsScale[0] = autocorrelationCoefficientsScale;
}
/*******************************************************************************************/
/* encodeSIDFrame: called at eache frame even if VADflag is set to active speech */
/* Update the previousVADflag and if curent is set to NOISE, compute the SID params */
/* parameters: */
/* -(i/o) DTXChannelContext: current DTX context, is updated by this function */
/* -(o) previousLSPCoefficients : 10 values in Q15, is updated by this function */
/* -(i/o) previousqLSPCoefficients : 10 values in Q15, is updated by this function */
/* -(i) VADflag : 1 active voice frame, 0 noise frame */
/* -(i/o) previousqLSF : set of 4 last frames qLSF in Q2.13, is updated */
/* -(i/o) excicationVector : in Q0, accessed in range [-L_PAST_EXCITATION,L_FRAME-1] */
/* -(o) qLPCoefficients : 20 values in Q3.12 the quantized LP coefficients */
/* -(o) bitStream : SID frame parameters on 2 bytes, may be null if no frame is to be */
/* transmitted */
/* -(o) bitStreamLength : length of bitStream buffer to be transmitted (2 for SID, 0 for */
/* untransmitted frame) */
/* */
/*******************************************************************************************/
void encodeSIDFrame(bcg729DTXChannelContextStruct *DTXChannelContext, word16_t *previousLSPCoefficients, word16_t *previousqLSPCoefficients, uint8_t VADflag, word16_t previousqLSF[MA_MAX_K][NB_LSP_COEFF], word16_t *excitationVector, word16_t *qLPCoefficients, uint8_t *bitStream, uint8_t *bitStreamLength) {
int i;
word32_t summedAutocorrelationCoefficients[NB_LSP_COEFF+1];
word16_t LPCoefficients[NB_LSP_COEFF]; /* in Q12 */
word16_t LSPCoefficients[NB_LSP_COEFF]; /* in Q15 */
word32_t reflectionCoefficient; /* not used here, by product of LP coefficients computation */
word32_t residualEnergy; /* in variable scale(summedAutocorrelationCoefficientsScale) computed together with LP coefficients */
int8_t summedAutocorrelationCoefficientsScale;
uint8_t frameType;
word32_t meanEnergy;
int8_t meanEnergyScale;
uint8_t quantizedResidualEnergy;
int8_t decodedLogEnergy;
uint8_t parameters[3]; /* array of the first 3 output parameters, 4th is in quantizedResidualEnergy */
word16_t interpolatedqLSP[NB_LSP_COEFF]; /* the interpolated qLSP used for first subframe in Q15 */
if (VADflag == 1) {/* this is a voice frame, just update the VADflag history and return */
DTXChannelContext->pseudoRandomSeed = CNG_DTX_RANDOM_SEED_INIT; /* re-init pseudo random seed at each active frame to keep CNG and DTX in sync */
DTXChannelContext->previousVADflag = 1;
return;
}
/* NOISE frame */
/* compute the autocorrelation coefficients sum on the current and previous frame */
sumAutocorrelationCoefficients((DTXChannelContext->autocorrelationCoefficients), DTXChannelContext->autocorrelationCoefficientsScale, 2,
summedAutocorrelationCoefficients, &summedAutocorrelationCoefficientsScale);
/* compute LP filter coefficients */
autoCorrelation2LP(summedAutocorrelationCoefficients, LPCoefficients, &reflectionCoefficient, &residualEnergy); /* output residualEnergy with the same scale of input summedAutocorrelationCoefficients */
/* determine type of frame SID or untrasmitted */
if (DTXChannelContext->previousVADflag == 1) { /* if previous frame was active : we must generate a SID frame spec B.10 */
frameType = SID_FRAME;
meanEnergy = residualEnergy;
meanEnergyScale = summedAutocorrelationCoefficientsScale;
quantizedResidualEnergy = residualEnergyQuantization(meanEnergy, meanEnergyScale, &decodedLogEnergy);
} else { /* previous frame was already non active, check if we have to generate a new SID frame according to spec 4.1.2-4.1.4 */
int8_t flag_chang = 0;
/* update meanEnergy using current and previous frame Energy : meanE = current+previous/2 : rescale both of them dividing by 2 and sum */
/* eqB14 doesn't divide by KE but it's done in eqB15, do it now */
if (summedAutocorrelationCoefficientsScale<DTXChannelContext->previousResidualEnergyScale) {
meanEnergyScale = summedAutocorrelationCoefficientsScale;
meanEnergy = ADD32(SHR(residualEnergy,1), VSHR32(DTXChannelContext->previousResidualEnergy, DTXChannelContext->previousResidualEnergyScale - summedAutocorrelationCoefficientsScale + 1));
} else {
meanEnergyScale = DTXChannelContext->previousResidualEnergyScale;
meanEnergy = ADD32(VSHR32(residualEnergy,summedAutocorrelationCoefficientsScale - DTXChannelContext->previousResidualEnergyScale + 1), SHR(DTXChannelContext->previousResidualEnergy, 1));
}
quantizedResidualEnergy = residualEnergyQuantization(meanEnergy, meanEnergyScale, &decodedLogEnergy);
/* comparison of LPC filters B4.1.3 : DTXChannelContext->SIDLPCoefficientAutocorrelation contains the last used filter LP coeffecients autocorrelation in Q20 */
if (compareLPCFilters(DTXChannelContext->SIDLPCoefficientAutocorrelation, summedAutocorrelationCoefficients, residualEnergy, THRESHOLD1_IN_Q20) != 0) {
flag_chang = 1;
}
/* comparison of the energies B4.1.4 */
if (ABS(DTXChannelContext->previousDecodedLogEnergy - decodedLogEnergy)>2) {
flag_chang = 1;
}
/* check if we have to transmit a SID frame eq B.11 */
DTXChannelContext->count_fr++;
if (DTXChannelContext->count_fr<3) { /* min 3 frames between 2 consecutive SID frames */
frameType = UNTRANSMITTED_FRAME;
} else {
if (flag_chang == 1) {
frameType = SID_FRAME;
} else {
frameType = UNTRANSMITTED_FRAME;
}
DTXChannelContext->count_fr = 3; /* counter on 8 bits, keep value low, we just need to know if it is > 3 */
}
}
/* generate the SID frame */
if (frameType == SID_FRAME) {
word32_t SIDLPCAutocorrelationCoefficients[NB_LSP_COEFF+1];
int8_t SIDLPCAutocorrelationCoefficientsScale;
word16_t pastAverageLPCoefficients[NB_LSP_COEFF]; /* in Q12 */
word32_t pastAverageReflectionCoefficient; /* not used here, by product of LP coefficients computation */
word32_t pastAverageResidualEnergy; /* not used here, by-product of LP coefficients computation */
/* reset frame count */
DTXChannelContext->count_fr = 0;
/*** compute the past average filter on the last 6 past frames ***/
sumAutocorrelationCoefficients(&(DTXChannelContext->autocorrelationCoefficients[1]), &(DTXChannelContext->autocorrelationCoefficientsScale[1]), 6,
SIDLPCAutocorrelationCoefficients, &SIDLPCAutocorrelationCoefficientsScale);
/* compute past average LP filter coefficients Ap in B4.2.2 */
autoCorrelation2LP(SIDLPCAutocorrelationCoefficients, pastAverageLPCoefficients, &pastAverageReflectionCoefficient, &pastAverageResidualEnergy); /* output residualEnergy with the same scale of input summedAutocorrelationCoefficients */
/* select coefficients according to eq B.17 we have Ap in SIDLPCoefficients and At in LPCoefficients, store result, in Q12 in SIDLPCoefficients */
/* check distance beetwen currently used filter and past filter : compute LPCoefficentAutocorrelation for the past average filter */
computeLPCoefficientAutocorrelation(pastAverageLPCoefficients, DTXChannelContext->SIDLPCoefficientAutocorrelation);
if (compareLPCFilters(DTXChannelContext->SIDLPCoefficientAutocorrelation, summedAutocorrelationCoefficients, residualEnergy, THRESHOLD3_IN_Q20) == 0) { /* use the past average filter */
/* generate LSP coefficient using the past LP coefficients */
if (!LP2LSPConversion(pastAverageLPCoefficients, LSPCoefficients)) {
/* unable to find the 10 roots repeat previous LSP */
memcpy(LSPCoefficients, previousqLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t));
}
/* LPCoefficientAutocorrelation are already in DTXChannelContext */
} else { /* use filter computed on current and previous frame */
/* compute the LPCoefficientAutocorrelation for this filter and store them in DTXChannel */
computeLPCoefficientAutocorrelation(LPCoefficients, DTXChannelContext->SIDLPCoefficientAutocorrelation);
/* generate LSP coefficient current LP coefficients */
if (!LP2LSPConversion(LPCoefficients, LSPCoefficients)) {
/* unable to find the 10 roots repeat previous LSP */
memcpy(LSPCoefficients, previousqLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t));
}
}
/* update previousLSP coefficient buffer */
memcpy(previousLSPCoefficients, LSPCoefficients, NB_LSP_COEFF*sizeof(word16_t));
/* LSP quantization */
noiseLSPQuantization(previousqLSF, LSPCoefficients, DTXChannelContext->qLSPCoefficients, parameters);
/* update previousDecodedLogEnergy and SIDGain */
DTXChannelContext->previousDecodedLogEnergy = decodedLogEnergy;
DTXChannelContext->currentSIDGain = SIDGainCodebook[quantizedResidualEnergy];
}
/* save current Frame Energy */
DTXChannelContext->previousResidualEnergy = residualEnergy;
DTXChannelContext->previousResidualEnergyScale = summedAutocorrelationCoefficientsScale;
/* apply target gain smoothing eq B.19 */
if(DTXChannelContext->previousVADflag == 1) {
DTXChannelContext->smoothedSIDGain = DTXChannelContext->currentSIDGain;
} else {
DTXChannelContext->smoothedSIDGain = SUB16(DTXChannelContext->smoothedSIDGain, (DTXChannelContext->smoothedSIDGain>>3));
DTXChannelContext->smoothedSIDGain = ADD16(DTXChannelContext->smoothedSIDGain, (DTXChannelContext->currentSIDGain>>3));
}
/* update excitation vector */
computeComfortNoiseExcitationVector(DTXChannelContext->smoothedSIDGain, &(DTXChannelContext->pseudoRandomSeed), excitationVector);
/* Interpolate qLSP and update the previousqLSP buffer */
interpolateqLSP(previousqLSPCoefficients, DTXChannelContext->qLSPCoefficients, interpolatedqLSP); /* in case of untransmitted frame, use qLSP generated for the last transmitted one */
for (i=0; i<NB_LSP_COEFF; i++) {
previousqLSPCoefficients[i] = DTXChannelContext->qLSPCoefficients[i];
}
/* first subframe */
qLSP2LP(interpolatedqLSP, qLPCoefficients);
/* second subframe */
qLSP2LP(DTXChannelContext->qLSPCoefficients, &(qLPCoefficients[NB_LSP_COEFF]));
/* set parameters into the bitStream if a frame must be transmitted */
if (frameType == SID_FRAME) {
*bitStreamLength = 2;
bitStream[0] = (((parameters[0]&0x01)<<7) /* L0 1 bit */
| ((parameters[1]&0x1F)<<2) /* L1 5 bits */
| ((parameters[2]>>2)%0x03)); /* L2 is 4 bits 2 MSB in this byte */
bitStream[1] = (((parameters[2]&0x03)<<6) /* 2 LSB of 4 bits L2 */
| ((quantizedResidualEnergy&0x1F)<<1)); /* Gain 5 bits, last bit is left to 0 */
} else {
*bitStreamLength = 0;
}
/* update the previousVADflag in context */
DTXChannelContext->previousVADflag = 0;
}

+ 61
- 0
src/dtx.h View File

@ -0,0 +1,61 @@
/*
dtx.h
Copyright (C) 2015 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef DTX_H
#define DTX_H
/*****************************************************************************/
/* initBcg729DTXChannel : create context structure and initialise it */
/* return value : */
/* - the DTX channel context data */
/* */
/*****************************************************************************/
bcg729DTXChannelContextStruct *initBcg729DTXChannel();
/*******************************************************************************************/
/* updateDTXContext : save autocorrelation value in DTX context as requested in B4.1.1 */
/* parameters: */
/* -(i/o) DTXChannelContext : the DTX context to be updated */
/* -(i) autocorrelationsCoefficients : 11 values of variable scale, values are copied */
/* in DTX context */
/* -(i) autocorrelationCoefficientsScale : the scale of previous buffer(can be <0) */
/* */
/*******************************************************************************************/
void updateDTXContext(bcg729DTXChannelContextStruct *DTXChannelContext, word32_t *autocorrelationCoefficients, int8_t autocorrelationCoefficientsScale);
/*******************************************************************************************/
/* encodeSIDFrame: called at eache frame even if VADflag is set to active speech */
/* Update the previousVADflag and if curent is set to NOISE, compute the SID params */
/* parameters: */
/* -(i/o) DTXChannelContext: current DTX context, is updated by this function */
/* -(o) previousLSPCoefficients : 10 values in Q15, is updated by this function */
/* -(i/o) previousqLSPCoefficients : 10 values in Q15, is updated by this function */
/* -(i) VADflag : 1 active voice frame, 0 noise frame */
/* -(i/o) previousqLSF : set of 4 last frames qLSF in Q2.13, is updated */
/* -(i/o) excicationVector : in Q0, accessed in range [-L_PAST_EXCITATION,L_FRAME-1] */
/* -(o) qLPCoefficients : 20 values in Q3.12 the quantized LP coefficients */
/* -(o) bitStream : SID frame parameters on 2 bytes, may be null if no frame is to be */
/* transmitted */
/* -(o) bitStreamLength : length of bitStream buffer to be transmitted (2 for SID, 0 for */
/* untransmitted frame) */
/* */
/*******************************************************************************************/
void encodeSIDFrame(bcg729DTXChannelContextStruct *DTXChannelContext, word16_t *previousLSPCoefficients, word16_t *previousqLSPCoefficients, uint8_t VADflag, word16_t previousqLSF[MA_MAX_K][NB_LSP_COEFF], word16_t *excitationVector, word16_t *qLPCoefficients, uint8_t *bitStream, uint8_t *bitStreamLength);
#endif /* ifndef DTX_H */

+ 108
- 4
src/encoder.c View File

@ -41,6 +41,9 @@
#include "computeAdaptativeCodebookGain.h"
#include "fixedCodebookSearch.h"
#include "gainQuantization.h"
#include "g729FixedPointMath.h"
#include "vad.h"
#include "dtx.h"
/* buffers allocation */
static const word16_t previousLSPInitialValues[NB_LSP_COEFF] = {30000, 26000, 21000, 15000, 8000, 0, -8000,-15000,-21000,-26000}; /* in Q0.15 the initials values for the previous LSP buffer */
@ -51,10 +54,11 @@ static const word16_t previousLSPInitialValues[NB_LSP_COEFF] = {30000, 26000, 21
/* - the encoder channel context data */
/* */
/*****************************************************************************/
bcg729EncoderChannelContextStruct *initBcg729EncoderChannel()
bcg729EncoderChannelContextStruct *initBcg729EncoderChannel(uint8_t enableVAD)
{
/* create the context structure */
bcg729EncoderChannelContextStruct *encoderChannelContext = malloc(sizeof(bcg729EncoderChannelContextStruct));
memset(encoderChannelContext, 0, sizeof(bcg729EncoderChannelContextStruct));
/* initialise statics buffers and variables */
memset(encoderChannelContext->signalBuffer, 0, (L_LP_ANALYSIS_WINDOW-L_FRAME)*sizeof(word16_t)); /* set to zero all the past signal */
@ -66,6 +70,13 @@ bcg729EncoderChannelContextStruct *initBcg729EncoderChannel()
memset(encoderChannelContext->excitationVector, 0, L_PAST_EXCITATION*sizeof(word16_t)); /* set to zero values of previous excitation vector */
memset(encoderChannelContext->targetSignal, 0, NB_LSP_COEFF*sizeof(word16_t)); /* set to zero values filter memory for the targetSignal computation */
encoderChannelContext->lastQuantizedAdaptativeCodebookGain = O2_IN_Q14; /* quantized gain is initialized at his minimum value: 0.2 */
if (enableVAD == 1) {
encoderChannelContext->VADChannelContext = initBcg729VADChannel();
encoderChannelContext->DTXChannelContext = initBcg729DTXChannel();
} else {
encoderChannelContext->VADChannelContext = NULL;
encoderChannelContext->DTXChannelContext = NULL;
}
/* initialisation of the differents blocs which need to be initialised */
initPreProcessing(encoderChannelContext);
@ -83,7 +94,15 @@ bcg729EncoderChannelContextStruct *initBcg729EncoderChannel()
/*****************************************************************************/
void closeBcg729EncoderChannel(bcg729EncoderChannelContextStruct *encoderChannelContext)
{
free(encoderChannelContext);
if (encoderChannelContext) {
if (encoderChannelContext->VADChannelContext) {
free(encoderChannelContext->VADChannelContext);
}
if (encoderChannelContext->DTXChannelContext) {
free(encoderChannelContext->DTXChannelContext);
}
free(encoderChannelContext);
}
}
/*****************************************************************************/
@ -95,13 +114,14 @@ void closeBcg729EncoderChannel(bcg729EncoderChannelContextStruct *encoderChannel
/* on 80 bits (10 8bits words) */
/* */
/*****************************************************************************/
void bcg729Encoder(bcg729EncoderChannelContextStruct *encoderChannelContext, int16_t inputFrame[], uint8_t bitStream[])
void bcg729Encoder(bcg729EncoderChannelContextStruct *encoderChannelContext, int16_t inputFrame[], uint8_t bitStream[], uint8_t *bitStreamLength)
{
int i;
uint16_t parameters[NB_PARAMETERS]; /* the output parameters in an array */
/* internal buffers which we do not need to keep between calls */
word16_t LPCoefficients[NB_LSP_COEFF]; /* the LP coefficients in Q3.12 */
word16_t LSFCoefficients[NB_LSP_COEFF]; /* the LSF coefficients in Q3.12 */
word16_t qLPCoefficients[2*NB_LSP_COEFF]; /* the quantized LP coefficients in Q3.12 computed from the qLSP one after interpolation: two sets, one for each subframe */
word16_t weightedqLPCoefficients[2*NB_LSP_COEFF]; /* the qLP coefficients in Q3.12 weighted according to spec A3.3.3 */
word16_t LSPCoefficients[NB_LSP_COEFF]; /* the LSP coefficients in Q15 */
@ -116,17 +136,101 @@ void bcg729Encoder(bcg729EncoderChannelContextStruct *encoderChannelContext, int
int parametersIndex = 4; /* index to insert parameters in the parameters output array */
word16_t impulseResponseInput[L_SUBFRAME]; /* input buffer for the impulse response computation: in Q12, 1 followed by all zeros see spec A3.5*/
/* used for VAD */
word32_t reflectionCoefficient = 0; /* in Q31, computed during LP generation */
word32_t autoCorrelationCoefficients[NB_LSP_COEFF+3]; /* if VAD is enabled we must compute 13 coefficients, 11 otherwise but used only internally by computeLP function in that case */
word32_t noLagAutoCorrelationCoefficients[NB_LSP_COEFF+3]; /* DTX must have access to autocorrelation Coefficients on which lag windowing as not been applied */
int8_t autoCorrelationCoefficientsScale; /* autocorrelation coefficients are normalised by computeLP, must get their scaling factor */
/*****************************************************************************************/
/*** on frame basis : preProcessing, LP Analysis, Open-loop pitch search ***/
preProcessing(encoderChannelContext, inputFrame, encoderChannelContext->signalLastInputFrame); /* output of the function in the signal buffer */
computeLP(encoderChannelContext->signalBuffer, LPCoefficients); /* use the whole signal Buffer for windowing and autocorrelation */
/* use the whole signal Buffer for windowing and autocorrelation */
/* autoCorrelation Coefficients are computed and used internally, in case of VAD we must compute and retrieve 13 coefficients, compute only 11 when VAD is disabled */
computeLP(encoderChannelContext->signalBuffer, LPCoefficients, &reflectionCoefficient, autoCorrelationCoefficients, noLagAutoCorrelationCoefficients, &autoCorrelationCoefficientsScale, (encoderChannelContext->VADChannelContext != NULL)?NB_LSP_COEFF+3:NB_LSP_COEFF+1);
/*** compute LSP: it might fail, get the previous one in this case ***/
if (!LP2LSPConversion(LPCoefficients, LSPCoefficients)) {
/* unable to find the 10 roots repeat previous LSP */
memcpy(LSPCoefficients, encoderChannelContext->previousLSPCoefficients, NB_LSP_COEFF*sizeof(word16_t));
}
/*********** VAD *****************/
if (encoderChannelContext->VADChannelContext != NULL) { /* if VAD is not enable, no context */
uint8_t VADflag = 1;
/* update DTX context */
updateDTXContext(encoderChannelContext->DTXChannelContext, noLagAutoCorrelationCoefficients, autoCorrelationCoefficientsScale);
/*** compute LSF in Q2.13 : lsf = arcos(lsp) range [0, Pi[ spec 3.2.4 eq18 ***/
/* TODO : remove it from LSPQuantizationFunction and perform it out of enableVAD test */
for (i=0; i<NB_LSP_COEFF; i++) {
LSFCoefficients[i] = g729Acos_Q15Q13(LSPCoefficients[i]);
}
VADflag = bcg729_vad(encoderChannelContext->VADChannelContext, reflectionCoefficient, LSFCoefficients, autoCorrelationCoefficients, autoCorrelationCoefficientsScale, encoderChannelContext->signalCurrentFrame);
/* call encodeSIDFrame even if it is a voice frame as it will update DTXContext with current VADflag */
encodeSIDFrame(encoderChannelContext->DTXChannelContext, encoderChannelContext->previousLSPCoefficients, encoderChannelContext->previousqLSPCoefficients, VADflag, encoderChannelContext->previousqLSF, &(encoderChannelContext->excitationVector[L_PAST_EXCITATION]), qLPCoefficients, bitStream, bitStreamLength);
if (VADflag == 0 ) { /* NOISE frame has been encoded */
word16_t residualSignal[L_FRAME];
/* update encoder context : generate weighted signal */
/*** Compute the weighted Quantized LP Coefficients according to spec A3.3.3 ***/
/* weightedqLPCoefficients[0] = qLPCoefficients[0]*Gamma^(i+1) (i=0..9) with Gamma = 0.75 in Q15 */
weightedqLPCoefficients[0] = MULT16_16_P15(qLPCoefficients[0], GAMMA_E1);
weightedqLPCoefficients[1] = MULT16_16_P15(qLPCoefficients[1], GAMMA_E2);
weightedqLPCoefficients[2] = MULT16_16_P15(qLPCoefficients[2], GAMMA_E3);
weightedqLPCoefficients[3] = MULT16_16_P15(qLPCoefficients[3], GAMMA_E4);
weightedqLPCoefficients[4] = MULT16_16_P15(qLPCoefficients[4], GAMMA_E5);
weightedqLPCoefficients[5] = MULT16_16_P15(qLPCoefficients[5], GAMMA_E6);
weightedqLPCoefficients[6] = MULT16_16_P15(qLPCoefficients[6], GAMMA_E7);
weightedqLPCoefficients[7] = MULT16_16_P15(qLPCoefficients[7], GAMMA_E8);
weightedqLPCoefficients[8] = MULT16_16_P15(qLPCoefficients[8], GAMMA_E9);
weightedqLPCoefficients[9] = MULT16_16_P15(qLPCoefficients[9], GAMMA_E10);
weightedqLPCoefficients[10] = MULT16_16_P15(qLPCoefficients[10], GAMMA_E1);
weightedqLPCoefficients[11] = MULT16_16_P15(qLPCoefficients[11], GAMMA_E2);
weightedqLPCoefficients[12] = MULT16_16_P15(qLPCoefficients[12], GAMMA_E3);
weightedqLPCoefficients[13] = MULT16_16_P15(qLPCoefficients[13], GAMMA_E4);
weightedqLPCoefficients[14] = MULT16_16_P15(qLPCoefficients[14], GAMMA_E5);
weightedqLPCoefficients[15] = MULT16_16_P15(qLPCoefficients[15], GAMMA_E6);
weightedqLPCoefficients[16] = MULT16_16_P15(qLPCoefficients[16], GAMMA_E7);
weightedqLPCoefficients[17] = MULT16_16_P15(qLPCoefficients[17], GAMMA_E8);
weightedqLPCoefficients[18] = MULT16_16_P15(qLPCoefficients[18], GAMMA_E9);
weightedqLPCoefficients[19] = MULT16_16_P15(qLPCoefficients[19], GAMMA_E10);
/*** Compute weighted signal according to spec A3.3.3, this function also compute LPResidualSignal(entire frame values) as specified in eq A.3 ***/
computeWeightedSpeech(encoderChannelContext->signalCurrentFrame, qLPCoefficients, weightedqLPCoefficients, &(encoderChannelContext->weightedInputSignal[MAXIMUM_INT_PITCH_DELAY]), residualSignal); /* weightedInputSignal contains MAXIMUM_INT_PITCH_DELAY values from previous frame, points to current frame */
/* update the target Signal : targetSignal = residualSignal - excitationVector */
for (subframeIndex=0; subframeIndex<L_FRAME; subframeIndex+=L_SUBFRAME) {
for (i=0; i<L_SUBFRAME; i++) {
encoderChannelContext->targetSignal[NB_LSP_COEFF+i] = SUB16(residualSignal[subframeIndex+i], encoderChannelContext->excitationVector[L_PAST_EXCITATION+subframeIndex+i]);
}
synthesisFilter(&(encoderChannelContext->targetSignal[NB_LSP_COEFF]), &(weightedqLPCoefficients[LPCoefficientsIndex]), &(encoderChannelContext->targetSignal[NB_LSP_COEFF]));
LPCoefficientsIndex+= NB_LSP_COEFF;
}
/*** memory updates ***/
/* shift left by L_FRAME the signal buffer */
memmove(encoderChannelContext->signalBuffer, &(encoderChannelContext->signalBuffer[L_FRAME]), (L_LP_ANALYSIS_WINDOW-L_FRAME)*sizeof(word16_t));
/* shift left by L_FRAME the weightedInputSignal buffer */
memmove(encoderChannelContext->weightedInputSignal, &(encoderChannelContext->weightedInputSignal[L_FRAME]), MAXIMUM_INT_PITCH_DELAY*sizeof(word16_t));
/* shift left by L_FRAME the excitationVector */
memmove(encoderChannelContext->excitationVector, &(encoderChannelContext->excitationVector[L_FRAME]), L_PAST_EXCITATION*sizeof(word16_t));
return;
}
}
/* set generated bitStream length: active voice is compressed into 80 bits */
*bitStreamLength = 10;
/*********** VAD *****************/
/*** LSPQuantization and compute L0, L1, L2, L3: the first four parameters ***/
LSPQuantization(encoderChannelContext, LSPCoefficients, qLSPCoefficients, parameters);


include/findOpenLoopPitchDelay.h → src/findOpenLoopPitchDelay.h View File


include/fixedCodebookSearch.h → src/fixedCodebookSearch.h View File


include/fixedPointMacros.h → src/fixedPointMacros.h View File


include/floatingPointMacros.h → src/floatingPointMacros.h View File


include/g729FixedPointMath.h → src/g729FixedPointMath.h View File


include/gainQuantization.h → src/gainQuantization.h View File


include/interpolateqLSP.h → src/interpolateqLSP.h View File


include/postFilter.h → src/postFilter.h View File


include/postProcessing.h → src/postProcessing.h View File


include/preProcessing.h → src/preProcessing.h View File


include/qLSP2LP.h → src/qLSP2LP.h View File


include/typedef.h → src/typedef.h View File


+ 56
- 0
src/utils.c View File

@ -52,6 +52,23 @@ void insertionSort(word16_t x[], int length)
return;
}
/*****************************************************************************/
/* getMinInArray : get the minimum value from an array */
/* parameters : */
/* -(i) x: the array to be searched */
/* -(i) length: the array length */
/* returns : the minimum value found in the array */
/* */
/*****************************************************************************/
word16_t getMinInArray(word16_t x[], int length) {
word16_t min = MAXINT16;
int i;
for (i=0; i<length; i++) {
if (x[i]<min) min = x[i];
}
return min;
}
/*****************************************************************************/
/* computeParity : compute parity for pitch delay adaptative codebook index */
/* XOR of the 6 MSB (pitchDelay on 8 bits) */
@ -298,6 +315,29 @@ void parametersArray2BitStream(uint16_t parameters[], uint8_t bitStream[])
return;
}
/*****************************************************************************/
/* CNGparametersArray2BitStream : convert array of parameters to bitStream */
/* according to spec B4.3 - Table B2 and following mapping of values */
/* 0 -> L0 (1 bit) */
/* 1 -> L1 (5 bits) */
/* 2 -> L2 (4 bits) */
/* 3 -> Gain (5 bits) */
/* parameters: */
/* -(i) parameters : 4 values parameters array */
/* -(o) bitStream : the 4 values streamed on 15 bits in a */
/* 2*8bits values array */
/* */
/*****************************************************************************/
void CNGparametersArray2BitStream(uint16_t parameters[], uint8_t bitStream[]) {
bitStream[0] = ((parameters[0]&((uint16_t) 0x1))<<7) |
((parameters[1]&((uint16_t) 0x1f))<<2) |
((parameters[2]>>2)&((uint16_t) 0x3));
bitStream[1] = ((parameters[2]&((uint16_t) 0x03))<<6) |
((parameters[3]&((uint16_t) 0x1f))<<1);
}
/*****************************************************************************/
/* parametersArray2BitStream : convert bitStream to an array of parameters */
/* reverse operation of previous funtion */
@ -327,3 +367,19 @@ void parametersBitStream2Array(uint8_t bitStream[], uint16_t parameters[])
return;
}
/*****************************************************************************/
/* pseudoRandom : generate pseudo random number as in spec 4.4.4 eq96 */
/* parameters: */
/* -(i/o) randomGeneratorSeed(updated by this function) */
/* return value : */
/* - a unsigned 16 bits pseudo random number */
/* */
/*****************************************************************************/
uint16_t pseudoRandom(uint16_t *randomGeneratorSeed)
{
/* pseudoRandomSeed is stored in an uint16_t var, we shall not worry about overflow here */
/* pseudoRandomSeed*31821 + 13849; */
*randomGeneratorSeed = MAC16_16(13849, (*randomGeneratorSeed), 31821);
return *randomGeneratorSeed;
}

include/utils.h → src/utils.h View File


+ 422
- 0
src/vad.c View File

@ -0,0 +1,422 @@
/*
vad.c
Voice Activity Detection
Copyright (C) 2015 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdlib.h>
#include "typedef.h"
#include "codecParameters.h"
#include "basicOperationsMacros.h"
#include "utils.h"
#include "g729FixedPointMath.h"
#include "codebooks.h"
#include "vad.h"
#define VOICE 1
#define NOISE 0
bcg729VADChannelContextStruct *initBcg729VADChannel() {
int i;
/* create the context structure */
bcg729VADChannelContextStruct *VADChannelContext = malloc(sizeof(bcg729VADChannelContextStruct));
memset(VADChannelContext, 0, sizeof(*VADChannelContext)); /* set meanLSF buffer to 0 */
VADChannelContext->frameCount = 0;
VADChannelContext->updateCount = 0;
for (i=0; i<N0; i++) {
VADChannelContext->EfBuffer[i] = MAXINT16;
}
VADChannelContext->SVDm1 = VOICE;
VADChannelContext->SVDm2 = VOICE;
VADChannelContext->Count_inert = 0;
VADChannelContext->secondStageVADSmoothingFlag = 1;
VADChannelContext->smoothingCounter = 0;
VADChannelContext->previousFrameEf = 0;
VADChannelContext->noiseContinuityCounter = 0;
return VADChannelContext;
}
/*******************************************************************************************/
/* multiBoundaryInitialVoiceActivityDecision as described in B3.5 */
/* parameters: */
/* -(i) deltaS spectral distorsion as decribed in B3.4.1 in Q13 */
/* -(i) deltaEf full band energy difference as described in B3.4.2 in Q11 */
/* -(i) deltaEl low band energy difference as described in B3.4.3 in Q11 */
/* -(i) deltaZC Zero Crossing difference as described in B3.4.4 in Q15 */
/* returns : Ivd as specified in B3.5 : VOICE or NOISE */
/* */
/*******************************************************************************************/
static uint8_t multiBoundaryInitialVoiceActivityDecision(word32_t deltaS, word16_t deltaEf, word16_t deltaEl, word16_t deltaZC) {
//word32_t acc1, acc2;
/* test the 14 conditions of B3.5 */
/* Note : the constant used in itu code are not the one in spec. Code seems erratic with comment irrelevant, use constant found in floating point version, annex C+ */
/* static FLOAT a[14] = { 1.750000e-03, -4.545455e-03, -2.500000e+01,
* ( 2.000000e+01, 0.000000e+00, 8.800000e+03,
* 0.000000e+0VADChannelContext->0, 2.5e+01, -2.909091e+01,
* 0.000000e+00, 1.400000e+04, 0.928571,
* -1.500000e+00, 0.714285};
*
* static FLOAT b[14] = { 0.00085, 0.001159091, -5.0,
* -6.0, -4.7, -12.2,
* 0.0009, -7.0, -4.8182,
* -5.3, -15.5, 1.14285,
* -9.0, -2.1428571};
* These constants are for Ef and El computed correctlVADChannelContext->y, we have Ef/10 and El/10 in buffers, and lsf normalised (/2pi)-> deltaS/4pi^2
*/
/* adjust input parameters */
word32_t deltaEf32 = MULT16_16(10, deltaEf); /* in Q11 */
word32_t deltaEl32 = MULT16_16(10, deltaEl); /* in Q11 */
deltaS = MULT16_32(830, deltaS); /* 830 is 1/(4*pi^2) in Q15, deltaS in Q28 now */
/* cond 1 : deltaS > a1*deltaZC + b1 */
if (deltaS > ADD32(MULT16_32_Q12(deltaZC, 58720), 228170)) { /* deltaS in Q28 - deltaZC in Q15*58720(1.75e-3 in Q25) >> 12 -> result in Q28 + 228170 (0.00085 in Q28) */
return VOICE;
}
/* cond 2 : deltaS > a2*deltaZC + b2 */
if (deltaS > ADD32(MULT16_32_Q12(deltaZC, -152520), 311141)) { /* deltaS in Q28 deltaZC in Q15*-152520(-4.545455e-03 in Q25) >> 12 -> result in Q28 + 311141 (0.001159091 in Q28) */
return VOICE;
}
/* cond 3 : deltaEf < a3*deltaZC + b3 */
if (deltaEf32 < ADD32(MULT16_32_Q15(deltaZC, -51200), -10240)) { /* deltaEf32 in Q11 - deltaZC in Q15*-51200(-2.50e+01 in Q11) >> 15 -> result in Q11 - 10240 (-5 in Q11) */
return VOICE;
}
/* cond 4 : deltaEf < a4*deltaZC + b4 */
if (deltaEf32 < ADD32(MULT16_32_Q15(deltaZC, 40960), -12288)) { /* deltaEf32 in Q11 - deltaZC in Q15*40960(2.0e+01 in Q11) >> 15 -> result in Q11 - 12288 (-6.0 in Q11) */
return VOICE;
}
/* cond 5 : deltaEf < b5 */
if (deltaEf32 < -9626) { /* deltaEf32 in Q11 - -4.7 in Q11 -> 9626 */
return VOICE;
}
/* cond 6 : deltaEf < a6*deltaS + b6 */
if (deltaEf32 < ADD32(MULT16_32_Q12(275,deltaS), -24986)) { /* deltaEf32 in Q11 - deltaS in Q28*275(8.8e+03 in Q-5) >> 12 -> result in Q11 - -24986 (-12.2 in Q11) */
return VOICE;
}
/* cond 7 : deltaS > b7 */
if (deltaS > 241592) { /* deltaS in Q28 - 0.0009 in Q28 -> 241592 */
return VOICE;
}
/* cond 8 : deltaEf < a8*deltaZC + b8 */
if (deltaEf32 < ADD32(MULT16_32_Q15(deltaZC, 51200), -14336)) { /* deltaEf32 in Q11 - deltaZC in Q15*51200(2.50e+01 in Q11) >> 15 -> result in Q11 - -14336 (-7 in Q11) */
return VOICE;
}
/* cond 9 : deltaEf < a9*deltaZC + b9 */
if (deltaEf32 < ADD32(MULT16_32_Q15(deltaZC, -59578), -9868)) { /* deltaEf32 in Q11 - deltaZC in Q15*59578(-2.909091e+01 in Q11) >> 15 -> result in Q11 - -9868 (-4.8182 in Q11) */
return VOICE;
}
/* cond 10 : deltaEf < b10 */
/* Note: cond 10 is totally useless : already covered by cond 5 before - skip it.*/
if (deltaEf32 < -10854) { /* deltaEf32 in Q11 - -5.3 in Q11 -> 10854 */
return VOICE;
}
/* cond 11 : deltaEl < a11*deltaS + b11 */
if (deltaEl32 < ADD32(MULT16_32_Q13(875,deltaS), -31744)) { /* deltaEl32 in Q11 - deltaS in Q28*875(1.4000e+04 in Q-4) >> 12 -> result in Q11 - -31744 (-15.5 in Q11) */
return VOICE;
}
/* cond 12 : deltaEl > a12*deltaEf + b12 */
if (deltaEl32 > ADD32(MULT16_32_Q15(30427, deltaEl32), 2341)) { /* deltaEl32 in Q11 - deltaEl32 in Q11*30427(0.928571 in Q15) >> 15 -> result in Q11 - 2341 (1.14285 in Q11) */
return VOICE;
}
/* cond 13 : deltaEl < a13*deltaEf + b13 */
if (deltaEl32 < ADD32(MULT16_32_Q14(-24576, deltaEl32), -18432)) { /* deltaEl32 in Q11 - deltaEl32 in Q11*-24576(-1.5 in Q14) >> 15 -> result in Q11 - -18432 (-9 in Q11) */
return VOICE;
}
/* cond 13 : deltaEl < a14*deltaEf + b14 */
if (deltaEl32 < ADD32(MULT16_32_Q15(23406, deltaEl32), -4389)) { /* deltaEl32 in Q11 - deltaEl32 in Q11*23406(0.714285 in Q15) >> 15 -> result in Q11 - -4389 (-2.1428571 in Q11) */
return VOICE;
}
/* no condition was true */
return NOISE;
}
/*******************************************************************************************/
/* bcg729_vad : voice activity detection from AnnexB */
/* parameters: */
/* -(i/o):VADChannelContext : context containing all informations needed for VAD */
/* -(i): reflectionCoefficient : in Q31 */
/* -(i): LSFCoefficients :10 Coefficient in Q2.13 in range [0,Pi[ */
/* -(i): autoCorrelationCoefficients : 13 coefficients of autoCorrelation */
/* -(i): autoCorrelationCoefficientsScale : scaling factor of previous coeffs */
/* -(i): signalCurrentFrame: the preprocessed signal in Q0, accessed in [-1, L_FRAME[ */
/* */
/* returns : 1 for active voice frame, 0 for silence frame */
/* */
/*******************************************************************************************/
uint8_t bcg729_vad(bcg729VADChannelContextStruct *VADChannelContext, word32_t reflectionCoefficient, word16_t *LSFCoefficients, word32_t *autoCorrelationCoefficients, int8_t autoCorrelationCoefficientsScale, const word16_t *signalCurrentFrame) {
word16_t Ef, deltaEf; /* full band energy/10 in Q11 eq B1 */
word16_t Emin; /* minimum Ef value of the last 128 frames */
word16_t El, deltaEl; /* low band energy/10 in Q11 eqB2 */
word16_t ZC, deltaZC; /* zero crossing rate in Q15 eq B3 */
word32_t deltaS; /* spectral distorsion in Q12 */
word32_t acc;
uint8_t Ivd = VOICE; /* Initial Voice activity decision : VOICE or NOISE, flag defined in B3.5 */
int i;
/*** parameters extraction B3.1 ***/
/* full band energy Ef (eq B1) = 10*log10(autoCorrelationCoefficient[0]/240), we compute Ef/10 in Q11 */
acc = SUB32(g729Log2_Q0Q16(autoCorrelationCoefficients[0]), (((int32_t)autoCorrelationCoefficientsScale)<<16)); /* acc = log2(R(0)) in Q16*/
acc = SHR32(SUB32(acc, LOG2_240_Q16),1); /* acc = log2(R(0)/240) in Q15 */
acc = MULT16_32_Q15(INV_LOG2_10_Q15, acc); /* acc Ef in Q15 */
Ef = (word16_t)(PSHR(acc,4));
/* store Ef in the rolling EfBuffer at position countFrame%N0 */
VADChannelContext->EfBuffer[(VADChannelContext->frameCount)%N0] = Ef;
/* low band energy El (eq B2)/10 in Q11 */
acc=MULT16_32_Q15(lowBandFilter[0], autoCorrelationCoefficients[0]);
for (i=1; i<NB_LSP_COEFF+3; i++) {
acc = MAC16_32_Q14(acc, lowBandFilter[i], autoCorrelationCoefficients[i]);
}
acc = SUB32(g729Log2_Q0Q16(acc), (((int32_t)autoCorrelationCoefficientsScale)<<16)); /* acc = log2(htRh) in Q16*/
acc = SHR32(SUB32(acc, LOG2_240_Q16),1); /* acc = log2(htRh/240) in Q15 */
acc = MULT16_32_Q15(INV_LOG2_10_Q15, acc); /* acc El in Q15 */
El = (word16_t)(PSHR(acc,4));
/* compute zero crossing rate ZC (eq B3) in Q15 : at each zero crossing, add 410 (1/80 in Q15)*/
ZC = 0;
for (i=0; i<L_FRAME; i++) {
if (MULT16_16(signalCurrentFrame[i-1], signalCurrentFrame[i])<0) {
ZC = ADD16(ZC,410); /* add 1/80 in Q15 */
}
}
/* B3.2 Initialisation of the running averages of background noise characteristics : End of init period (32 first frames) */
if (VADChannelContext->frameCount == Ni) { /* complete initialisations */
word16_t meanEn = 0;
if (VADChannelContext->nbValidInitFrame>0) {/* check if we had a valid frame during init */
meanEn = (word16_t)DIV32(VADChannelContext->initEfSum, VADChannelContext->nbValidInitFrame);
VADChannelContext->meanZC = (word16_t)DIV32(VADChannelContext->initZCSum, VADChannelContext->nbValidInitFrame);
for (i=0; i<NB_LSP_COEFF; i++) {
VADChannelContext->meanLSF[i] = (word16_t)DIV32(VADChannelContext->initLSFSum[i], VADChannelContext->nbValidInitFrame);
}
/* spec B3.2 describe a mechanism for initialisation of meanEl and meanEf which is not implemented in ITU code */
/* ITU code does: meanEf = meanEn-1 and meanEl = meanEn - 1.2, just do that */
/* it looks like the case in wich meanEn>T2 (5.5dB) is considered always true which is certainly not the case */
VADChannelContext->meanEf = SUB16(meanEn, 2048); /* -1 in Q11 (K4 if K4 is in Q27 in the spec)*/
VADChannelContext->meanEl = SUB16(meanEn, 2458); /* -1.2 in Q11 (K5 if K5 is in Q27 in the spec)*/
} else {/* if we have no valid frames */
VADChannelContext->frameCount = 0; /* as done in Appendix II : reset frameCount to restart init period */
}
}
/* B3.2 Initialisation of the running averages of background noise characteristics : during init period(32 first frames) */
if (VADChannelContext->frameCount < Ni) { /* initialisation is still on going for running averages */
if (Ef<3072) { /* Ef stores 1/10 of full band energy in Q11, frames are valid only when Ef>15dB, 3072 is 1.5 in Q11 */
Ivd = NOISE;
} else {
Ivd = VOICE;
VADChannelContext->nbValidInitFrame++;
VADChannelContext->initEfSum = ADD32(VADChannelContext->initEfSum, Ef);
VADChannelContext->initZCSum = ADD32(VADChannelContext->initZCSum, ZC);
for (i=0; i<NB_LSP_COEFF; i++) {
VADChannelContext->initLSFSum[i] = ADD32(VADChannelContext->initLSFSum[i], LSFCoefficients[i]);
}
}
/* context updates */
VADChannelContext->frameCount++;
VADChannelContext->previousFrameEf = Ef;
VADChannelContext -> SVDm2 = VADChannelContext -> SVDm1;
VADChannelContext -> SVDm1 = Ivd;
return Ivd;
}
/* B3.3 Generating the long term minimum energy (real computation of the minimum over the last 128 values, no trick as suggested in the spec) */
Emin = getMinInArray(VADChannelContext->EfBuffer, N0);
/* B3.4.1 spectral distorsion deltaS */
deltaS = 0;
for (i=0; i<NB_LSP_COEFF; i++) {
word16_t acc16;
acc16 = SUB16(LSFCoefficients[i], VADChannelContext->meanLSF[i]);
deltaS = MAC16_16_Q13(deltaS, acc16, acc16);
}
/* B3.4.2 deltaEf */
deltaEf = SUB16(VADChannelContext->meanEf, Ef); /* in Q11 */
/* B3.4.3 deltaEf */
deltaEl = SUB16(VADChannelContext->meanEl, El); /* in Q11 */
/* B3.4.2 deltaEf */
deltaZC = SUB16(VADChannelContext->meanZC, ZC); /* in Q15 */
if (Ef<3072) { /* Ef stores 1/10 of full band energy in Q11, frames are valid only when Ef>15dB, 3072 is 1.5 in Q11 */
Ivd = NOISE;
} else {
Ivd = multiBoundaryInitialVoiceActivityDecision(deltaS, deltaEf, deltaEl, deltaZC);
}
/* B3.6 : Voice Activity Decision Smoothing */
/* Appendix II hysteresis II 5.2 as implemented in ITU code, description in appendix has a test on meanEf which is not implemented in example code */
if (Ivd == VOICE) {
VADChannelContext->Count_inert=0;
}
if ((Ivd == NOISE) && (VADChannelContext->Count_inert < 6)) {
VADChannelContext->Count_inert++;
Ivd = VOICE;
}
/* first stage of VAD smoothing : code add a test on Ef>15 (21 in the floating version?!?) not documented */
if ((Ivd == NOISE) && (VADChannelContext->SVDm1) && (deltaEf>410) && (Ef>3072)) { /* deltaEf is (meanEf - Ef)/10 in Q11, test is Ef > meanEf + 2, 410 is 0.2 in Q11 - 3072 is 1.5 in Q11 */
Ivd = VOICE;
}
/* second stage of VAD smoothing */
if ((VADChannelContext->secondStageVADSmoothingFlag == 1)
&& (Ivd == NOISE)
&& (VADChannelContext->SVDm1 == VOICE)
&& (VADChannelContext->SVDm2 == VOICE)
&& (ABS(SUB16(Ef, VADChannelContext->previousFrameEf)) <= 614)) { /* |Ef - meanEf|<=3 -> 614 is 0.3 in Q11 */
Ivd = VOICE;
VADChannelContext->smoothingCounter++;
if (VADChannelContext->smoothingCounter<=4) {
VADChannelContext->secondStageVADSmoothingFlag = 1;
} else {
VADChannelContext->secondStageVADSmoothingFlag = 0;
VADChannelContext->smoothingCounter = 0;
}
} else {
VADChannelContext->secondStageVADSmoothingFlag = 1;
}
/* third stage of VAD smoothing */
if (Ivd == NOISE) {
VADChannelContext->noiseContinuityCounter++;
}
if ( (Ivd == VOICE)
&& (VADChannelContext->noiseContinuityCounter > 10) /* Cs > N2 */
&& (SUB16(Ef, VADChannelContext->previousFrameEf) <= 614)) { /* Ef - prevEf <= T5(3.0) : 614 is 0.3 in Q11 */
Ivd = NOISE;
VADChannelContext->noiseContinuityCounter = 0;
VADChannelContext->Count_inert = 6; /* added by appendix II*/
}
if (Ivd == VOICE) {
VADChannelContext->noiseContinuityCounter = 0;
}
/* forth stage of VAD smoothing is not implemented in appendix II */
/* update the running averages B3.7 : note ITU implementation differs from spec, not only Ef < meanEf + 3dB is tested but also ReflectionCoefficient < 0.75 and deltaS < 0.002532959 */
if ( (SUB16(Ef, 614) < VADChannelContext->meanEf) /* 614 is 0.3 in Q11 : Ef and meanEf are 1/10 of real Ef and meanEf, so 0.3 instead of 3, all in Q11 */
&& (reflectionCoefficient < 1610612736) ) { /* in Q31, 0.75 is 1610612736 */
/* Note : G729 Appendix II suggest that the test on deltaS is not relevant and prevent good detection in very noisy environment : remove it */
// && (deltaS < 819)) { /* deltaS is computed using non normalised LSF so compare with 4*pi^2*0.002532959 = 819 in Q13 as ITU code normalise LSF dividing them by 2*Pi */
/* all beta Coefficient in Q15 */
word16_t betaE, betaZC, betaLSF; /* parameter used for first order auto-regressive update scheme, note betaEf and betaEl are the same: betaE */
word16_t betaEComplement, betaZCComplement, betaLSFComplement; /* these are the (1 - betaXX) */
/* update number of update performed (Cn in spec B3.7) */
VADChannelContext->updateCount++;
/* according to spec, based on Cn (updateCount) value we must use a different set of coefficient, none of them is defined in the spec, all values are picked from ITU code */
if (VADChannelContext->updateCount<20) {
betaE = 24576; /* 0.75 */
betaEComplement = 8192; /* 1-0.75 */
betaZC = 26214; /* 0.8 */
betaZCComplement = 6554; /* 1-0.8 */
betaLSF = 19661; /* 0.6 */
betaLSFComplement = 13107; /* 1-0.6 */
} else if (VADChannelContext->updateCount<30) {
betaE = 31130; /* 0.95 */
betaEComplement = 1638; /* 1-0.95 */
betaZC = 30147; /* 0.92 */
betaZCComplement = 2621; /* 1-0.92 */
betaLSF = 21299; /* 0.65 */
betaLSFComplement = 11469; /* 1-0.65 */
} else if (VADChannelContext->updateCount<40) {
betaE = 31785; /* 0.97 */
betaEComplement = 983; /* 1-0.97 */
betaZC = 30802; /* 0.94 */
betaZCComplement = 1966; /* 1-0.94 */
betaLSF = 22938; /* 0.7 */
betaLSFComplement = 9830 ; /* 1-0.7 */
} else if (VADChannelContext->updateCount<50) {
betaE = 32440; /* 0.99 */
betaEComplement = 328; /* 1-0.99 */
betaZC = 31457; /* 0.96 */
betaZCComplement = 1311; /* 1-0.96 */
betaLSF = 24756; /* 0.75 */
betaLSFComplement = 8192; /* 1-0.75 */
} else if (VADChannelContext->updateCount<60) {
betaE = 32604; /* 0.995 */
betaEComplement = 164; /* 1-0.995 */
betaZC = 32440; /* 0.99 */
betaZCComplement = 328; /* 1-0.99 */
betaLSF = 24576; /* 0.75 */
betaLSFComplement = 8192; /* 1-0.75 */
} else {
betaE = 32702; /* 0.998 */ /* note : in ITU code betaE and betaZC seems to be swaped on this last case, this implementation swap them back */
betaEComplement = 66; /* 1-0.998 */
betaZC = 32604; /* 0.995 */
betaZCComplement = 164; /* 1-0.995 */
betaLSF = 24576; /* 0.75 */
betaLSFComplement = 8192; /* 1-0.75 */
}
VADChannelContext->meanEf = ADD16(MULT16_16_Q15(VADChannelContext->meanEf, betaE), MULT16_16_Q15(Ef, betaEComplement));
VADChannelContext->meanEl = ADD16(MULT16_16_Q15(VADChannelContext->meanEl, betaE), MULT16_16_Q15(El, betaEComplement));
VADChannelContext->meanZC = ADD16(MULT16_16_Q15(VADChannelContext->meanZC, betaZC), MULT16_16_Q15(ZC, betaZCComplement));
for (i=0; i<NB_LSP_COEFF; i++) {
VADChannelContext->meanLSF[i] = ADD16(MULT16_16_Q15(VADChannelContext->meanLSF[i], betaLSF), MULT16_16_Q15(LSFCoefficients[i], betaLSFComplement));
}
}
/* further update of meanEf and updatedFrame, implementation differs from spec again, stick to ITU code */
if ( (VADChannelContext->frameCount>N0)
&&( ((VADChannelContext->meanEf<Emin) && (deltaS < 819)) /* deltaS < 0.002532959 -> 819 is 0.002532959*4*pi^2 in Q13 */
||(VADChannelContext->meanEf > ADD16(Emin, 2048)))) { /* meanEf > Emin + 10 : 2048 is 1 in Q11, Ef is 1/10 of real one */
VADChannelContext->meanEf = Emin;
VADChannelContext->updateCount = 0;
}
/* context updates */
VADChannelContext->frameCount++;
VADChannelContext->previousFrameEf = Ef;
VADChannelContext -> SVDm2 = VADChannelContext -> SVDm1;
VADChannelContext -> SVDm1 = Ivd;
return Ivd;
}

+ 42
- 0
src/vad.h View File

@ -0,0 +1,42 @@
/*
vad.h
Copyright (C) 2011 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef VAD_H
#define VAD_H
/*****************************************************************************/
/* initBcg729VADChannel : create context structure and initialise it */
/* return value : */
/* - the VAD channel context data */
/* */
/*****************************************************************************/
bcg729VADChannelContextStruct *initBcg729VADChannel();
/*******************************************************************************************/
/* bcg729_vad : voice activity detection from AnnexB */
/* parameters: */
/* -(i/o):VADChannelContext : context containing all informations needed for VAD */
/* */
/* returns : 1 for active voice frame, 0 for silence frame */
/* */
/*******************************************************************************************/
uint8_t bcg729_vad(bcg729VADChannelContextStruct *VADChannelContext, word32_t reflectionCoefficient, word16_t *LSFCoefficients, word32_t *autoCorrelationCoefficients, int8_t autoCorrelationCoefficientsScale, const word16_t *signalCurrentFrame);
#endif /* ifndef VAD_H */

+ 5
- 2
test/bin/Makefile.am View File

@ -1,6 +1,6 @@
check_PROGRAMS=adaptativeCodebookSearchTest computeAdaptativeCodebookGainTest computeLPTest computeWeightedSpeechTest decodeAdaptativeCodeVectorTest decodeFixedCodeVectorTest decodeGainsTest decodeLSPTest \
decoderTest encoderTest decoderMultiChannelTest encoderMultiChannelTest findOpenLoopPitchDelayTest fixedCodebookSearchTest g729FixedPointMathTest gainQuantizationTest interpolateqLSPAndConvert2LPTest \
LP2LSPConversionTest LPSynthesisFilterTest LSPQuantizationTest postFilterTest postProcessingTest preProcessingTest
LP2LSPConversionTest LPSynthesisFilterTest LSPQuantizationTest postFilterTest postProcessingTest preProcessingTest computeNoiseExcitationTest CNGdecoderTest encoderVADTest
util_src=$(top_srcdir)/test/src/testUtils.c
adaptativeCodebookSearchTest_SOURCES=$(top_srcdir)/test/src/adaptativeCodebookSearchTest.c $(util_src)
@ -12,6 +12,7 @@ decodeFixedCodeVectorTest_SOURCES=$(top_srcdir)/test/src/decodeFixedCodeVectorTe
decodeGainsTest_SOURCES=$(top_srcdir)/test/src/decodeGainsTest.c $(util_src)
decodeLSPTest_SOURCES=$(top_srcdir)/test/src/decodeLSPTest.c $(util_src)
decoderTest_SOURCES=$(top_srcdir)/test/src/decoderTest.c $(util_src)
CNGdecoderTest_SOURCES=$(top_srcdir)/test/src/CNGdecoderTest.c $(util_src)
decoderMultiChannelTest_SOURCES=$(top_srcdir)/test/src/decoderMultiChannelTest.c $(util_src)
encoderTest_SOURCES=$(top_srcdir)/test/src/encoderTest.c $(util_src)
encoderMultiChannelTest_SOURCES=$(top_srcdir)/test/src/encoderMultiChannelTest.c $(util_src)
@ -27,7 +28,9 @@ LSPQuantizationTest_SOURCES=$(top_srcdir)/test/src/LSPQuantizationTest.c $(util_
postFilterTest_SOURCES=$(top_srcdir)/test/src/postFilterTest.c $(util_src)
postProcessingTest_SOURCES=$(top_srcdir)/test/src/postProcessingTest.c $(util_src)
preProcessingTest_SOURCES=$(top_srcdir)/test/src/preProcessingTest.c $(util_src)
computeNoiseExcitationTest_SOURCES=$(top_srcdir)/test/src/computeNoiseExcitationTest.c $(util_src)
encoderVADTest_SOURCES=$(top_srcdir)/test/src/encoderVADTest.c $(util_src)
LDADD= $(top_builddir)/src/libbcg729.la
AM_CPPFLAGS=-I$(top_srcdir)/include/
AM_CPPFLAGS=-I$(top_srcdir)/include/ -I$(top_srcdir)/src/
AM_LDFLAGS=-all-static

+ 143
- 0
test/src/CNGdecoderTest.c View File

@ -0,0 +1,143 @@
/*
decoderTest.c
Copyright (C) 2011 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*****************************************************************************/
/* */
/* Test Program for decoder */
/* Input: 15 parameters and the frame erasure flag on each row of a */
/* a text CSV file. */
/* Ouput: the reconstructed signal : each frame (80 16 bits PCM values) */
/* on a row of a text CSV file */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "typedef.h"
#include "codecParameters.h"
#include "utils.h"
#include "testUtils.h"
#include "bcg729/decoder.h"
int main(int argc, char *argv[] )
{
/*** get calling argument ***/
char *filePrefix;
getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */
/*** input and output file pointers ***/
FILE *fpInput;
FILE *fpOutput;
FILE *fpBinOutput;
/*** input and output buffers ***/
uint16_t inputBuffer[NB_PARAMETERS+2]; /* input buffer: an array containing the 15 parameters and the frame erasure flag and VAD flag */
uint8_t bitStream[10]; /* binary input for the decoder */
int16_t outputBuffer[L_FRAME]; /* output buffer: the reconstructed signal */
/*** inits ***/
/* open the input file */
if ( (fpInput = fopen(argv[1], "r")) == NULL) {
printf("%s - Error: can't open file %s\n", argv[0], argv[1]);
exit(-1);
}
/* create the output file(filename is the same than input file with the .out extension) */
char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char));
sprintf(outputFile, "%s.out",filePrefix);
if ( (fpOutput = fopen(outputFile, "w")) == NULL) {
printf("%s - Error: can't create file %s\n", argv[0], outputFile);
exit(-1);
}
sprintf(outputFile, "%s.pcm",filePrefix);
if ( (fpBinOutput = fopen(outputFile, "wb")) == NULL) {
printf("%s - Error: can't create file %s\n", argv[0], outputFile);
exit(-1);
}
/*** init of the tested bloc ***/
bcg729DecoderChannelContextStruct *decoderChannelContext = initBcg729DecoderChannel();
/*** initialisation complete ***/
/* perf measurement */
clock_t start, end;
double cpu_time_used=0.0;
int framesNbr =0;
/* increase LOOP_N to increase input length and perform a more accurate profiling or perf measurement */
#define LOOP_N 1
int j;
for (j=0; j<LOOP_N; j++) {
/* perf measurement */
/*** loop over input file ***/
while(fscanf(fpInput, "%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd", &(inputBuffer[0]), &(inputBuffer[1]), &(inputBuffer[2]), &(inputBuffer[3]), &(inputBuffer[4]), &(inputBuffer[5]), &(inputBuffer[6]), &(inputBuffer[7]), &(inputBuffer[8]), &(inputBuffer[9]), &(inputBuffer[10]), &(inputBuffer[11]), &(inputBuffer[12]), &(inputBuffer[13]), &(inputBuffer[14]), &(inputBuffer[15]), &(inputBuffer[16]))==17) /* index 4 and 5 are inverted to get P0 in 4 and P1 in 5 in the array */
{ /* input buffer contains the parameters and in [15] the frame erasure flag */
int i;
framesNbr++;
if (inputBuffer[16]==1) { /* active frame */
parametersArray2BitStream(inputBuffer, bitStream);
} else { /* SID frame */
if (inputBuffer[16]==0) {/* non transmitted frame */
inputBuffer[15] = 1;
} else { /* actual SID frame */
CNGparametersArray2BitStream(inputBuffer, bitStream);
}
}
start = clock();
bcg729Decoder(decoderChannelContext, inputBuffer[15]==0?bitStream:NULL, inputBuffer[15], inputBuffer[16]!=1?1:0, outputBuffer);
end = clock();
cpu_time_used += ((double) (end - start));
/* write the output to the output files (only on first loop of perf measurement)*/
if (j==0) {
fprintf(fpOutput,"%d",outputBuffer[0]);
for (i=1; i<L_FRAME; i++) {
fprintf(fpOutput,",%d",outputBuffer[i]);
}
fprintf(fpOutput,"\n");
/* write the ouput to raw data file */
fwrite(outputBuffer, sizeof(int16_t), L_FRAME, fpBinOutput);
}
}
/* perf measurement */
rewind(fpInput);
}
closeBcg729DecoderChannel(decoderChannelContext);
/* Perf measurement: uncomment next line to print cpu usage */
printf("Decode %d frames in %f seconds : %f us/frame\n", framesNbr, cpu_time_used/CLOCKS_PER_SEC, cpu_time_used*1000000/((double)framesNbr*CLOCKS_PER_SEC));
/* perf measurement */
exit (0);
}

+ 8
- 1
test/src/computeLPTest.c View File

@ -33,6 +33,7 @@
#include "typedef.h"
#include "codecParameters.h"
#include "basicOperationsMacros.h"
#include "testUtils.h"
@ -76,6 +77,12 @@ int main(int argc, char *argv[] )
while(1) /* infinite loop, escape condition is in the reading of data */
{
int i;
/* by-products of computeLP used for VAD/DTX, not tested here */
word32_t reflectionCoefficient;
word32_t autoCorrelationCoefficients[11];
word32_t noLagAutoCorrelationCoefficients[11];
int8_t autoCorrelationCoefficientsScale;
/* read the input data until we have some */
if (fscanf(fpInput,"%hd",&(inputBuffer[0])) != 1) break;
for (i=1; i<L_LP_ANALYSIS_WINDOW; i++) {
@ -83,7 +90,7 @@ int main(int argc, char *argv[] )
}
/* call the preProcessing function: output will replace the input in the buffer */
computeLP(inputBuffer, LPCoefficients);
computeLP(inputBuffer, LPCoefficients, &reflectionCoefficient, autoCorrelationCoefficients, noLagAutoCorrelationCoefficients, &autoCorrelationCoefficientsScale, 11);
/* write the output to the output file */
fprintf(fpOutput,"%d", LPCoefficients[0]);


+ 105
- 0
test/src/computeNoiseExcitationTest.c View File

@ -0,0 +1,105 @@
/*
computeNoiseExcitationTest.c
Copyright (C) 2011 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*****************************************************************************/
/* */
/* Test Program for computeLP Bloc */
/* Input: a CSV text with 236 values of 16 bits : */
/* - target gain in Q3 */
/* - pseudo random generator seed */
/* - 234 values of excitation vector buffer(154 past, 80 current) */
/* Ouput: - updated pseudo random generator seed */
/* - 234 16 bits values of updated excitation vector */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "typedef.h"
#include "codecParameters.h"
#include "testUtils.h"
#include "cng.h"
int main(int argc, char *argv[] )
{
/*** get calling argument ***/
char *filePrefix;
getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */
/*** input and output file pointers ***/
FILE *fpInput;
FILE *fpOutput;
/*** input and output buffers ***/
word16_t inputBuffer[L_PAST_EXCITATION+L_FRAME]; /* used for input and output, in Q0 */
word16_t targetGain; /* input in Q3 */
uint16_t randomGeneratorSeed;
/*** inits ***/
/* open the input file */
if ( (fpInput = fopen(argv[1], "r")) == NULL) {
printf("%s - Error: can't open file %s\n", argv[0], argv[1]);
exit(-1);
}
/* create the output file(filename is the same than input file with the .out extension) */
char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char));
sprintf(outputFile, "%s.out",filePrefix);
if ( (fpOutput = fopen(outputFile, "w")) == NULL) {
printf("%s - Error: can't create file %s\n", argv[0], outputFile);
exit(-1);
}
/*** init of the tested bloc ***/
/*** initialisation complete ***/
/*** loop over input file ***/
while(1) /* infinite loop, escape condition is in the reading of data */
{
int i;
/* read the input data until we have some */
if (fscanf(fpInput,"%hd",&targetGain) != 1) break;
if (fscanf(fpInput,",%hd",&randomGeneratorSeed) != 1) break;
for (i=0; i<L_PAST_EXCITATION+L_FRAME; i++) {
if (fscanf(fpInput,",%hd",&(inputBuffer[i])) != 1) break;
}
/* call the tested function: output will replace the input in the buffer */
computeComfortNoiseExcitationVector(targetGain, &randomGeneratorSeed, &(inputBuffer[L_PAST_EXCITATION]));
/* write the output to the output file */
//fprintf(fpOutput,"%d", (int16_t)randomGeneratorSeed);
fprintf(fpOutput,"%d", (int16_t)inputBuffer[L_PAST_EXCITATION]);
for (i=L_PAST_EXCITATION+1; i<L_PAST_EXCITATION+L_FRAME; i++) {
fprintf(fpOutput,",%d", inputBuffer[i]);
}
fprintf(fpOutput,"\n");
}
exit (0);
}

+ 1
- 1
test/src/decoderMultiChannelTest.c View File

@ -120,7 +120,7 @@ int main(int argc, char *argv[] )
parametersArray2BitStream(inputBuffer, bitStream);
start = clock();
bcg729Decoder(decoderChannelContext[k], bitStream, inputBuffer[15], outputBuffer);
bcg729Decoder(decoderChannelContext[k], bitStream, inputBuffer[15], 0, outputBuffer);
end = clock();
cpu_time_used += ((double) (end - start));


+ 2
- 2
test/src/decoderTest.c View File

@ -103,7 +103,7 @@ int main(int argc, char *argv[] )
parametersArray2BitStream(inputBuffer, bitStream);
start = clock();
bcg729Decoder(decoderChannelContext, bitStream, inputBuffer[15], outputBuffer);
bcg729Decoder(decoderChannelContext, bitStream, inputBuffer[15], 0, outputBuffer);
end = clock();
cpu_time_used += ((double) (end - start));
@ -127,7 +127,7 @@ int main(int argc, char *argv[] )
closeBcg729DecoderChannel(decoderChannelContext);
/* Perf measurement: uncomment next line to print cpu usage */
// printf("Decode %d frames in %f seconds : %f us/frame\n", framesNbr, cpu_time_used/CLOCKS_PER_SEC, cpu_time_used*1000000/((double)framesNbr*CLOCKS_PER_SEC));
printf("Decode %d frames in %f seconds : %f us/frame\n", framesNbr, cpu_time_used/CLOCKS_PER_SEC, cpu_time_used*1000000/((double)framesNbr*CLOCKS_PER_SEC));
/* perf measurement */
exit (0);
}


+ 15
- 11
test/src/encoderMultiChannelTest.c View File

@ -93,7 +93,7 @@ int main(int argc, char *argv[] )
}
/*** init of the tested bloc ***/
encoderChannelContext[i] = initBcg729EncoderChannel();
encoderChannelContext[i] = initBcg729EncoderChannel(0);
}
@ -122,6 +122,8 @@ int main(int argc, char *argv[] )
while(1) /* infinite loop, escape condition is in the reading of data */
{
int i;
uint8_t bitStreamLength;
/* read the input data until we have some */
if (inputIsBinary[k]) {
if (fread(inputBuffer, sizeof(int16_t), L_FRAME, fpInput[k]) != L_FRAME) break;
@ -135,21 +137,23 @@ int main(int argc, char *argv[] )
framesNbr++;
start = clock();
bcg729Encoder(encoderChannelContext[k], inputBuffer, bitStream);
bcg729Encoder(encoderChannelContext[k], inputBuffer, bitStream, &bitStreamLength);
end = clock();
cpu_time_used += ((double) (end - start));
/* convert bitStream output in an array for easier debug */
parametersBitStream2Array(bitStream, outputBuffer);
if (j==0) {
/* write the output to the output file */
fprintf(fpOutput[k],"%d",outputBuffer[0]);
for (i=1; i<NB_PARAMETERS; i++) {
fprintf(fpOutput[k],",%d",outputBuffer[i]);
if (bitStreamLength == 10) {
/* convert bitStream output in an array for easier debug */
parametersBitStream2Array(bitStream, outputBuffer);
if (j==0) {
/* write the output to the output file */
fprintf(fpOutput[k],"%d",outputBuffer[0]);
for (i=1; i<NB_PARAMETERS; i++) {
fprintf(fpOutput[k],",%d",outputBuffer[i]);
}
fprintf(fpOutput[k],",0\n");
}
fprintf(fpOutput[k],",0\n");
}
}
/* we've reach the end of the file */


+ 28
- 12
test/src/encoderTest.c View File

@ -83,12 +83,12 @@ int main(int argc, char *argv[] )
}
/*** init of the tested bloc ***/
bcg729EncoderChannelContextStruct *encoderChannelContext = initBcg729EncoderChannel();
bcg729EncoderChannelContextStruct *encoderChannelContext = initBcg729EncoderChannel(0);
/*** initialisation complete ***/
/* perf measurement */
clock_t start, end;
double cpu_time_used=0.0;
double cpu_time_used=0.0f;
int framesNbr =0;
/* increase LOOP_N to increase input length and perform a more accurate profiling or perf measurement */
#define LOOP_N 1
@ -100,6 +100,8 @@ int main(int argc, char *argv[] )
while(1) /* infinite loop, escape condition is in the reading of data */
{
int i;
uint8_t bitStreamLength;
/* read the input data until we have some */
if (inputIsBinary) {
if (fread(inputBuffer, sizeof(int16_t), L_FRAME, fpInput) != L_FRAME) break;
@ -114,22 +116,36 @@ int main(int argc, char *argv[] )
framesNbr++;
start = clock();
bcg729Encoder(encoderChannelContext, inputBuffer, bitStream);
bcg729Encoder(encoderChannelContext, inputBuffer, bitStream, &bitStreamLength);
end = clock();
cpu_time_used += ((double) (end - start));
/* convert bitStream output in an array for easier debug */
parametersBitStream2Array(bitStream, outputBuffer);
if (j==0) {
/* write the output to the output file */
fprintf(fpOutput,"%d",outputBuffer[0]);
for (i=1; i<NB_PARAMETERS; i++) {
fprintf(fpOutput,",%d",outputBuffer[i]);
if (bitStreamLength == 10) {
parametersBitStream2Array(bitStream, outputBuffer);
if (j==0) {
/* write the output to the output file */
fprintf(fpOutput,"%d",outputBuffer[0]);
for (i=1; i<NB_PARAMETERS; i++) {
fprintf(fpOutput,",%d",outputBuffer[i]);
}
fprintf(fpOutput,",0\n");
}
fprintf(fpOutput,",0\n");
} else if (bitStreamLength == 2) {
/* write the output to the output file */
fprintf(fpOutput,"%d,%d,%d,%d",(bitStream[0]>>7)&0x01, (bitStream[0]>>2)&0x1F, ((bitStream[0]&0x03)<<2) | ((bitStream[1]>>6)&0x03), ((bitStream[1])>>1)&0x1F);
for (i=4; i<NB_PARAMETERS; i++) {
fprintf(fpOutput,",0"); /* just get the correct number of parameters */
}
fprintf(fpOutput,",0,2\n");
} else { /* bitstream to 0, un transmitted frame */
for (i=0; i<NB_PARAMETERS; i++) {
fprintf(fpOutput,"0,"); /* just get the correct number of parameters */
}
fprintf(fpOutput,"1,0\n");
}
}
/* perf measurement */
@ -137,7 +153,7 @@ int main(int argc, char *argv[] )
}
closeBcg729EncoderChannel(encoderChannelContext);
/* Perf measurement: uncomment next line to print cpu usage */
// printf("Encode %d frames in %f seconds : %f us/frame\n", framesNbr, cpu_time_used/CLOCKS_PER_SEC, cpu_time_used*1000000/((double)framesNbr*CLOCKS_PER_SEC));
printf("Encode %d frames in %f seconds : %f us/frame\n", framesNbr, cpu_time_used/CLOCKS_PER_SEC, cpu_time_used*1000000/((double)framesNbr*CLOCKS_PER_SEC));
/* perf measurement */
exit (0);


+ 161
- 0
test/src/encoderVADTest.c View File

@ -0,0 +1,161 @@
/*
encoderTest.c
Copyright (C) 2011 Belledonne Communications, Grenoble, France
Author : Johan Pascal
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*****************************************************************************/
/* */
/* Test Program for encoder */
/* Input: the reconstructed signal : each frame (80 16 bits PCM values) */
/* on a row of a text CSV file */
/* Output: 15 parameters on each row of a text CSV file. */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "typedef.h"
#include "codecParameters.h"
#include "utils.h"
#include "testUtils.h"
#include "bcg729/encoder.h"
FILE *fpOutput;
int main(int argc, char *argv[] )
{
/*** get calling argument ***/
char *filePrefix;
getArgument(argc, argv, &filePrefix); /* check argument and set filePrefix if needed */
/*** input and output file pointers ***/
FILE *fpInput;
/*** input and output buffers ***/
int16_t inputBuffer[L_FRAME]; /* output buffer: the signal */
uint8_t bitStream[10]; /* binary output of the encoder */
uint16_t outputBuffer[NB_PARAMETERS]; /* output buffer: an array containing the 15 parameters */
/*** inits ***/
/* open the input file */
uint16_t inputIsBinary = 0;
if (argv[1][strlen(argv[1])-1] == 'n') { /* input filename and by n, it's probably a .in : CSV file */
if ( (fpInput = fopen(argv[1], "r")) == NULL) {
printf("%s - Error: can't open file %s\n", argv[0], argv[1]);
exit(-1);
}
} else { /* it's probably a binary file */
inputIsBinary = 1;
if ( (fpInput = fopen(argv[1], "rb")) == NULL) {
printf("%s - Error: can't open file %s\n", argv[0], argv[1]);
exit(-1);
}
}
/* create the output file(filename is the same than input file with the .out extension) */
char *outputFile = malloc((strlen(filePrefix)+5)*sizeof(char));
sprintf(outputFile, "%s.out",filePrefix);
if ( (fpOutput = fopen(outputFile, "w")) == NULL) {
printf("%s - Error: can't create file %s\n", argv[0], outputFile);
exit(-1);
}
/*** init of the tested bloc ***/
bcg729EncoderChannelContextStruct *encoderChannelContext = initBcg729EncoderChannel(1);
/*** initialisation complete ***/
/* perf measurement */
clock_t start, end;
double cpu_time_used=0.0f;
int framesNbr =0;
/* increase LOOP_N to increase input length and perform a more accurate profiling or perf measurement */
#define LOOP_N 1
int j;
for (j=0; j<LOOP_N; j++) {
/* perf measurement */
/*** loop over input file ***/
while(1) /* infinite loop, escape condition is in the reading of data */
{
int i;
uint8_t bitStreamLength;
/* read the input data until we have some */
if (inputIsBinary) {
if (fread(inputBuffer, sizeof(int16_t), L_FRAME, fpInput) != L_FRAME) break;
} else {
if (fscanf(fpInput,"%hd",&(inputBuffer[0])) != 1) break;
for (i=1; i<L_FRAME; i++) {
if (fscanf(fpInput,",%hd",&(inputBuffer[i])) != 1) break;
}
}
framesNbr++;
start = clock();
bcg729Encoder(encoderChannelContext, inputBuffer, bitStream, &bitStreamLength);
end = clock();
cpu_time_used += ((double) (end - start));
/* convert bitStream output in an array for easier debug */
if (bitStreamLength == 10) {
parametersBitStream2Array(bitStream, outputBuffer);
if (j==0) {
/* write the output to the output file */
fprintf(fpOutput,"%d",outputBuffer[0]);
for (i=1; i<NB_PARAMETERS; i++) {
fprintf(fpOutput,",%d",outputBuffer[i]);
}
fprintf(fpOutput,",0,1\n");
}
} else if (bitStreamLength == 2) {
/* write the output to the output file */
fprintf(fpOutput,"%d,%d,%d,%d",(bitStream[0]>>7)&0x01, (bitStream[0]>>2)&0x1F, ((bitStream[0]&0x03)<<2) | ((bitStream[1]>>6)&0x03), ((bitStream[1])>>1)&0x1F);
for (i=4; i<NB_PARAMETERS; i++) {
fprintf(fpOutput,",0"); /* just get the correct number of parameters */
}
fprintf(fpOutput,",0,2\n");
} else { /* bitstream to 0, un transmitted frame */
for (i=0; i<NB_PARAMETERS; i++) {
fprintf(fpOutput,"0,"); /* just get the correct number of parameters */
}
fprintf(fpOutput,"1,0\n");
}
}
/* perf measurement */
rewind(fpInput);
}
closeBcg729EncoderChannel(encoderChannelContext);
/* Perf measurement: uncomment next line to print cpu usage */
printf("Encode %d frames in %f seconds : %f us/frame\n", framesNbr, cpu_time_used/CLOCKS_PER_SEC, cpu_time_used*1000000/((double)framesNbr*CLOCKS_PER_SEC));
/* perf measurement */
exit (0);
}

+ 3
- 1
test/testCampaign View File

@ -132,6 +132,7 @@ if ((@ARGV < 1) || (@ARGV > 2))
print "# testCampaign [-s] <test name> #\n";
print "# test name in the following list : #\n";
print "# - decoder #\n";
print "# - CNGdecoder #\n";
print "# - decodeLSP #\n";
print "# - interpolateqLSPAndConvert2LP #\n";
print "# - decodeAdaptativeCodeVector #\n";
@ -198,7 +199,8 @@ if ($ARGV[0] eq "-s") {
"LPSynthesisFilter" => [0,0],
"postFilter" => [0,0],
"postProcessing" => [0,0],
"decoder" => [0,0]
"decoder" => [0,0],
"CNGdecoder" => [0,0]
);


Loading…
Cancel
Save