/* Generates excitation for CNG LPC synthesis */ SKP_INLINE void SKP_Silk_CNG_exc( SKP_int16 residual[], /* O CNG residual signal Q0 */ SKP_int32 exc_buf_Q10[], /* I Random samples buffer Q10 */ SKP_int32 Gain_Q16, /* I Gain to apply */ SKP_int length, /* I Length */ SKP_int32 *rand_seed /* I/O Seed to random index generator */ ) { SKP_int32 seed; SKP_int i, idx, exc_mask; exc_mask = CNG_BUF_MASK_MAX; while( exc_mask > length ) { exc_mask = SKP_RSHIFT( exc_mask, 1 ); } seed = *rand_seed; for( i = 0; i < length; i++ ) { seed = SKP_RAND( seed ); idx = ( SKP_int )( SKP_RSHIFT( seed, 24 ) & exc_mask ); SKP_assert( idx >= 0 ); SKP_assert( idx <= CNG_BUF_MASK_MAX ); residual[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( exc_buf_Q10[ idx ], Gain_Q16 ), 10 ) ); } *rand_seed = seed; }
int main( int argc, char* argv[] ) { unsigned long tottime, starttime; double filetime; size_t counter; SKP_int32 args, totPackets, i, k; SKP_int16 ret, len, tot_len; SKP_int16 nBytes; SKP_uint8 payload[ MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES * ( MAX_LBRR_DELAY + 1 ) ]; SKP_uint8 *payloadEnd = NULL, *payloadToDec = NULL; SKP_uint8 FECpayload[ MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES ], *payloadPtr; SKP_int16 nBytesFEC; SKP_int16 nBytesPerPacket[ MAX_LBRR_DELAY + 1 ], totBytes; SKP_int16 out[ ( ( FRAME_LENGTH_MS * MAX_API_FS_KHZ ) << 1 ) * MAX_INPUT_FRAMES ], *outPtr; char speechOutFileName[ 150 ], bitInFileName[ 150 ]; FILE *bitInFile, *speechOutFile; SKP_int32 packetSize_ms=0, API_Fs_Hz = 0; SKP_int32 decSizeBytes; void *psDec; SKP_float loss_prob; SKP_int32 frames, lost, quiet; SKP_SILK_SDK_DecControlStruct DecControl; if( argc < 3 ) { print_usage( argv ); exit( 0 ); } /* default settings */ quiet = 0; loss_prob = 0.0f; /* get arguments */ args = 1; strcpy( bitInFileName, argv[ args ] ); args++; strcpy( speechOutFileName, argv[ args ] ); args++; while( args < argc ) { if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-loss" ) == 0 ) { sscanf( argv[ args + 1 ], "%f", &loss_prob ); args += 2; } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-Fs_API" ) == 0 ) { sscanf( argv[ args + 1 ], "%d", &API_Fs_Hz ); args += 2; } else if( SKP_STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-quiet" ) == 0 ) { quiet = 1; args++; } else { printf( "Error: unrecognized setting: %s\n\n", argv[ args ] ); print_usage( argv ); exit( 0 ); } } if( !quiet ) { printf("********** Silk Decoder (Fixed Point) v %s ********************\n", SKP_Silk_SDK_get_version()); printf("********** Compiled for %d bit cpu *******************************\n", (int)sizeof(void*) * 8 ); printf( "Input: %s\n", bitInFileName ); printf( "Output: %s\n", speechOutFileName ); } /* Open files */ bitInFile = fopen( bitInFileName, "rb" ); if( bitInFile == NULL ) { printf( "Error: could not open input file %s\n", bitInFileName ); exit( 0 ); } /* Check Silk header */ { char header_buf[ 50 ]; fread(header_buf, sizeof(char), 1, bitInFile); header_buf[ strlen( "" ) ] = '\0'; /* Terminate with a null character */ if( strcmp( header_buf, "" ) != 0 ) { counter = fread( header_buf, sizeof( char ), strlen( "!SILK_V3" ), bitInFile ); header_buf[ strlen( "!SILK_V3" ) ] = '\0'; /* Terminate with a null character */ if( strcmp( header_buf, "!SILK_V3" ) != 0 ) { /* Non-equal strings */ printf( "Error: Wrong Header %s\n", header_buf ); exit( 0 ); } } else { counter = fread( header_buf, sizeof( char ), strlen( "#!SILK_V3" ), bitInFile ); header_buf[ strlen( "#!SILK_V3" ) ] = '\0'; /* Terminate with a null character */ if( strcmp( header_buf, "#!SILK_V3" ) != 0 ) { /* Non-equal strings */ printf( "Error: Wrong Header %s\n", header_buf ); exit( 0 ); } } } speechOutFile = fopen( speechOutFileName, "wb" ); if( speechOutFile == NULL ) { printf( "Error: could not open output file %s\n", speechOutFileName ); exit( 0 ); } /* Set the samplingrate that is requested for the output */ if( API_Fs_Hz == 0 ) { DecControl.API_sampleRate = 24000; } else { DecControl.API_sampleRate = API_Fs_Hz; } /* Initialize to one frame per packet, for proper concealment before first packet arrives */ DecControl.framesPerPacket = 1; /* Create decoder */ ret = SKP_Silk_SDK_Get_Decoder_Size( &decSizeBytes ); if( ret ) { printf( "\nSKP_Silk_SDK_Get_Decoder_Size returned %d", ret ); } psDec = malloc( decSizeBytes ); /* Reset decoder */ ret = SKP_Silk_SDK_InitDecoder( psDec ); if( ret ) { printf( "\nSKP_Silk_InitDecoder returned %d", ret ); } totPackets = 0; tottime = 0; payloadEnd = payload; /* Simulate the jitter buffer holding MAX_FEC_DELAY packets */ for( i = 0; i < MAX_LBRR_DELAY; i++ ) { /* Read payload size */ counter = fread( &nBytes, sizeof( SKP_int16 ), 1, bitInFile ); #ifdef _SYSTEM_IS_BIG_ENDIAN swap_endian( &nBytes, 1 ); #endif /* Read payload */ counter = fread( payloadEnd, sizeof( SKP_uint8 ), nBytes, bitInFile ); if( ( SKP_int16 )counter < nBytes ) { break; } nBytesPerPacket[ i ] = nBytes; payloadEnd += nBytes; totPackets++; } while( 1 ) { /* Read payload size */ counter = fread( &nBytes, sizeof( SKP_int16 ), 1, bitInFile ); #ifdef _SYSTEM_IS_BIG_ENDIAN swap_endian( &nBytes, 1 ); #endif if( nBytes < 0 || counter < 1 ) { break; } /* Read payload */ counter = fread( payloadEnd, sizeof( SKP_uint8 ), nBytes, bitInFile ); if( ( SKP_int16 )counter < nBytes ) { break; } /* Simulate losses */ rand_seed = SKP_RAND( rand_seed ); if( ( ( ( float )( ( rand_seed >> 16 ) + ( 1 << 15 ) ) ) / 65535.0f >= ( loss_prob / 100.0f ) ) && ( counter > 0 ) ) { nBytesPerPacket[ MAX_LBRR_DELAY ] = nBytes; payloadEnd += nBytes; } else { nBytesPerPacket[ MAX_LBRR_DELAY ] = 0; } if( nBytesPerPacket[ 0 ] == 0 ) { /* Indicate lost packet */ lost = 1; /* Packet loss. Search after FEC in next packets. Should be done in the jitter buffer */ payloadPtr = payload; for( i = 0; i < MAX_LBRR_DELAY; i++ ) { if( nBytesPerPacket[ i + 1 ] > 0 ) { starttime = GetHighResolutionTime(); SKP_Silk_SDK_search_for_LBRR( payloadPtr, nBytesPerPacket[ i + 1 ], ( i + 1 ), FECpayload, &nBytesFEC ); tottime += GetHighResolutionTime() - starttime; if( nBytesFEC > 0 ) { payloadToDec = FECpayload; nBytes = nBytesFEC; lost = 0; break; } } payloadPtr += nBytesPerPacket[ i + 1 ]; } } else { lost = 0; nBytes = nBytesPerPacket[ 0 ]; payloadToDec = payload; } /* Silk decoder */ outPtr = out; tot_len = 0; starttime = GetHighResolutionTime(); if( lost == 0 ) { /* No Loss: Decode all frames in the packet */ frames = 0; do { /* Decode 20 ms */ ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 0, payloadToDec, nBytes, outPtr, &len ); if( ret ) { printf( "\nSKP_Silk_SDK_Decode returned %d", ret ); } frames++; outPtr += len; tot_len += len; if( frames > MAX_INPUT_FRAMES ) { /* Hack for corrupt stream that could generate too many frames */ outPtr = out; tot_len = 0; frames = 0; } /* Until last 20 ms frame of packet has been decoded */ } while( DecControl.moreInternalDecoderFrames ); } else { /* Loss: Decode enough frames to cover one packet duration */ for( i = 0; i < DecControl.framesPerPacket; i++ ) { /* Generate 20 ms */ ret = SKP_Silk_SDK_Decode( psDec, &DecControl, 1, payloadToDec, nBytes, outPtr, &len ); if( ret ) { printf( "\nSKP_Silk_Decode returned %d", ret ); } outPtr += len; tot_len += len; } } packetSize_ms = tot_len / ( DecControl.API_sampleRate / 1000 ); tottime += GetHighResolutionTime() - starttime; totPackets++; /* Write output to file */ #ifdef _SYSTEM_IS_BIG_ENDIAN swap_endian( out, tot_len ); #endif fwrite( out, sizeof( SKP_int16 ), tot_len, speechOutFile ); /* Update buffer */ totBytes = 0; for( i = 0; i < MAX_LBRR_DELAY; i++ ) { totBytes += nBytesPerPacket[ i + 1 ]; } SKP_memmove( payload, &payload[ nBytesPerPacket[ 0 ] ], totBytes * sizeof( SKP_uint8 ) ); payloadEnd -= nBytesPerPacket[ 0 ]; SKP_memmove( nBytesPerPacket, &nBytesPerPacket[ 1 ], MAX_LBRR_DELAY * sizeof( SKP_int16 ) ); if( !quiet ) { fprintf( stderr, "\rPackets decoded: %d", totPackets ); } }
void SKP_Silk_PLC_conceal( SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ SKP_int16 signal[], /* O concealed signal */ SKP_int length /* I length of residual */ ) { SKP_int i, j, k; SKP_int16 *B_Q14, exc_buf[ MAX_FRAME_LENGTH ], *exc_buf_ptr; SKP_int16 rand_scale_Q14, A_Q12_tmp[ MAX_LPC_ORDER ]; SKP_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15; SKP_int lag, idx, shift1, shift2; SKP_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr, Atmp; SKP_int32 sig_Q10[ MAX_FRAME_LENGTH ], *sig_Q10_ptr, LPC_exc_Q10, LPC_pred_Q10, LTP_pred_Q14; SKP_Silk_PLC_struct *psPLC; psPLC = &psDec->sPLC; /* Update LTP buffer */ SKP_memcpy( psDec->sLTP_Q16, &psDec->sLTP_Q16[ psDec->frame_length ], psDec->frame_length * sizeof( SKP_int32 ) ); /* LPC concealment. Apply BWE to previous LPC */ SKP_Silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, BWE_COEF_Q16 ); /* Find random noise component */ /* Scale previous excitation signal */ exc_buf_ptr = exc_buf; for( k = ( NB_SUBFR >> 1 ); k < NB_SUBFR; k++ ) { for( i = 0; i < psDec->subfr_length; i++ ) { exc_buf_ptr[ i ] = ( SKP_int16 )SKP_RSHIFT( SKP_SMULWW( psDec->exc_Q10[ i + k * psDec->subfr_length ], psPLC->prevGain_Q16[ k ] ), 10 ); } exc_buf_ptr += psDec->subfr_length; } /* Find the subframe with lowest energy of the last two and use that as random noise generator */ SKP_Silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psDec->subfr_length ); SKP_Silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psDec->subfr_length ], psDec->subfr_length ); if( SKP_RSHIFT( energy1, shift2 ) < SKP_RSHIFT( energy1, shift2 ) ) { /* First sub-frame has lowest energy */ rand_ptr = &psDec->exc_Q10[ SKP_max_int( 0, 3 * psDec->subfr_length - RAND_BUF_SIZE ) ]; } else { /* Second sub-frame has lowest energy */ rand_ptr = &psDec->exc_Q10[ SKP_max_int( 0, psDec->frame_length - RAND_BUF_SIZE ) ]; } /* Setup Gain to random noise component */ B_Q14 = psPLC->LTPCoef_Q14; rand_scale_Q14 = psPLC->randScale_Q14; /* Setup attenuation gains */ harm_Gain_Q15 = HARM_ATT_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; if( psDec->prev_sigtype == SIG_TYPE_VOICED ) { rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; } else { rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; } /* First Lost frame */ if( psDec->lossCnt == 0 ) { rand_scale_Q14 = (1 << 14 ); /* Reduce random noise Gain for voiced frames */ if( psDec->prev_sigtype == SIG_TYPE_VOICED ) { for( i = 0; i < LTP_ORDER; i++ ) { rand_scale_Q14 -= B_Q14[ i ]; } rand_scale_Q14 = SKP_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ rand_scale_Q14 = ( SKP_int16 )SKP_RSHIFT( SKP_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); } /* Reduce random noise for unvoiced frames with high LPC gain */ if( psDec->prev_sigtype == SIG_TYPE_UNVOICED ) { SKP_int32 invGain_Q30, down_scale_Q30; SKP_Silk_LPC_inverse_pred_gain( &invGain_Q30, psPLC->prevLPC_Q12, psDec->LPC_order ); down_scale_Q30 = SKP_min_32( SKP_RSHIFT( ( 1 << 30 ), LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); down_scale_Q30 = SKP_max_32( SKP_RSHIFT( ( 1 << 30 ), LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); down_scale_Q30 = SKP_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); rand_Gain_Q15 = SKP_RSHIFT( SKP_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); } } rand_seed = psPLC->rand_seed; lag = SKP_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); psDec->sLTP_buf_idx = psDec->frame_length; /***************************/ /* LTP synthesis filtering */ /***************************/ sig_Q10_ptr = sig_Q10; for( k = 0; k < NB_SUBFR; k++ ) { /* Setup pointer */ pred_lag_ptr = &psDec->sLTP_Q16[ psDec->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; for( i = 0; i < psDec->subfr_length; i++ ) { rand_seed = SKP_RAND( rand_seed ); idx = SKP_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; /* Unrolled loop */ LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); pred_lag_ptr++; /* Generate LPC residual */ LPC_exc_Q10 = SKP_LSHIFT( SKP_SMULWB( rand_ptr[ idx ], rand_scale_Q14 ), 2 ); /* Random noise part */ LPC_exc_Q10 = SKP_ADD32( LPC_exc_Q10, SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ) ); /* Harmonic part */ /* Update states */ psDec->sLTP_Q16[ psDec->sLTP_buf_idx ] = SKP_LSHIFT( LPC_exc_Q10, 6 ); psDec->sLTP_buf_idx++; /* Save LPC residual */ sig_Q10_ptr[ i ] = LPC_exc_Q10; } sig_Q10_ptr += psDec->subfr_length; /* Gradually reduce LTP gain */ for( j = 0; j < LTP_ORDER; j++ ) { B_Q14[ j ] = SKP_RSHIFT( SKP_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); } /* Gradually reduce excitation gain */ rand_scale_Q14 = SKP_RSHIFT( SKP_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); /* Slowly increase pitch lag */ psPLC->pitchL_Q8 += SKP_SMULWB( psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); psPLC->pitchL_Q8 = SKP_min_32( psPLC->pitchL_Q8, SKP_LSHIFT( SKP_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); lag = SKP_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); } /***************************/ /* LPC synthesis filtering */ /***************************/ sig_Q10_ptr = sig_Q10; /* Preload LPC coeficients to array on stack. Gives small performance gain */ SKP_memcpy( A_Q12_tmp, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( SKP_int16 ) ); SKP_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ for( k = 0; k < NB_SUBFR; k++ ) { for( i = 0; i < psDec->subfr_length; i++ ){ /* unrolled */ Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 0 ] ); /* read two coefficients at once */ LPC_pred_Q10 = SKP_SMULWB( psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], Atmp ); LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], Atmp ); Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 2 ] ); LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], Atmp ); LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], Atmp ); Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 4 ] ); LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], Atmp ); LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], Atmp ); Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 6 ] ); LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], Atmp ); LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], Atmp ); Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 8 ] ); LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], Atmp ); LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], Atmp ); for( j = 10 ; j < psDec->LPC_order ; j+=2 ) { Atmp = *( ( SKP_int32* )&A_Q12_tmp[ j ] ); LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 1 - j ], Atmp ); LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 2 - j ], Atmp ); } /* Add prediction to LPC residual */ sig_Q10_ptr[ i ] = SKP_ADD32( sig_Q10_ptr[ i ], LPC_pred_Q10 ); /* Update states */ psDec->sLPC_Q14[ MAX_LPC_ORDER + i ] = SKP_LSHIFT( sig_Q10_ptr[ i ], 4 ); } sig_Q10_ptr += psDec->subfr_length; /* Update LPC filter state */ SKP_memcpy( psDec->sLPC_Q14, &psDec->sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( SKP_int32 ) ); } /* Scale with Gain */ for( i = 0; i < psDec->frame_length; i++ ) { signal[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( sig_Q10[ i ], psPLC->prevGain_Q16[ NB_SUBFR - 1 ] ), 10 ) ); } /**************************************/ /* Update states */ /**************************************/ psPLC->rand_seed = rand_seed; psPLC->randScale_Q14 = rand_scale_Q14; for( i = 0; i < NB_SUBFR; i++ ) { psDecCtrl->pitchL[ i ] = lag; } }