pure sdk for main
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
#ifndef _ADPCM_CODE_H_
|
||||
#define _ADPCM_CODE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "ringbuf.h"
|
||||
#include "lowcfe.h"
|
||||
|
||||
struct adpcm_channel {
|
||||
int32_t pcmdata; // current PCM value
|
||||
int32_t shaping_weight, error; // for noise shaping
|
||||
int8_t index; // current index into step size table
|
||||
};
|
||||
|
||||
struct adpcm_context {
|
||||
struct adpcm_channel channels [2];
|
||||
int num_channels, sample_rate, config_flags;
|
||||
int16_t *dynamic_shaping_array, last_shaping_weight;
|
||||
int static_shaping_weight;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct adpcm_context *normal_cnxt;
|
||||
struct adpcm_context *rddancy_cnxt;
|
||||
TYPE_RINGBUF *ringbuf_original;
|
||||
TYPE_RINGBUF *ringbuf_encode;
|
||||
uint32_t rddancy_num;
|
||||
}AdpcmEncoder;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *rddancy_encbuf;
|
||||
uint32_t rddancy_num;
|
||||
uint32_t rddancy_encode_len;
|
||||
uint32_t rddancy_encbuf_num;
|
||||
uint32_t rddancy_encbuf_pos;
|
||||
uint32_t block_size;
|
||||
uint8_t plc_sta;
|
||||
LowcFE_c *lowcfe;
|
||||
int16_t *decode_buf;
|
||||
}AdpcmDecoder;
|
||||
|
||||
typedef uint64_t rms_error_t; // best if "double" or "uint64_t", "float" okay in a pinch
|
||||
#define MAX_RMS_ERROR UINT64_MAX
|
||||
|
||||
#define NOISE_SHAPING_OFF 0 // flat noise (no shaping)
|
||||
#define NOISE_SHAPING_STATIC 0x100 // static 1st-order shaping (configurable, highpass default)
|
||||
#define NOISE_SHAPING_DYNAMIC 0x200 // dynamically tilted noise based on signal
|
||||
|
||||
#define LOOKAHEAD_DEPTH 0x0ff // depth of search
|
||||
#define LOOKAHEAD_EXHAUSTIVE 0x800 // full breadth of search (all branches taken)
|
||||
#define LOOKAHEAD_NO_BRANCHING 0x400 // no branches taken (internal use only!)
|
||||
|
||||
#define CLIP(data, min, max) \
|
||||
if ((data) > (max)) data = max; \
|
||||
else if ((data) < (min)) data = min;
|
||||
|
||||
#define NIBBLE_TO_DELTA(b,n) ((n)<(1<<((b)-1))?(n)+1:(1<<((b)-1))-1-(n))
|
||||
#define DELTA_TO_NIBBLE(b,d) ((d)<0?(1<<((b)-1))-1-(d):(d)-1)
|
||||
|
||||
#define NOISE_SHAPING_ENABLED (NOISE_SHAPING_DYNAMIC | NOISE_SHAPING_STATIC)
|
||||
|
||||
#define adpcm_malloc malloc
|
||||
#define adpcm_free free
|
||||
|
||||
static void win_average_buffer (float *samples, int sample_count, int half_width);
|
||||
int adpcm_encode(AdpcmEncoder *adpcm_enc, uint8_t *outbuf, int *outbufsize, int16_t *inbuf, int inbufcount, int bps);
|
||||
int adpcm_decode(AdpcmDecoder *adpcm_dec, int16_t *outbuf, const uint8_t *inbuf, uint32_t inbufsize, int bps);
|
||||
AdpcmEncoder *adpcm_encoder_create(int sample_rate, int lookahead, int noise_shaping, int block_size, int redundancy_num);
|
||||
AdpcmDecoder *adpcm_decoder_create(int block_size, int redundancy_num);
|
||||
int adpcm_decode_plc(AdpcmDecoder *adpcm_dec, int16_t *outbuf);
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** ADPCM-XQ **** //
|
||||
// Xtreme Quality ADPCM Encoder/Decoder //
|
||||
// Copyright (c) 2024 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// adpcm-dns.c
|
||||
|
||||
// This module handles the implementation of "dynamic noise shaping" which is
|
||||
// designed to move the spectrum of the quantization noise introduced by lossy
|
||||
// compression up or down in frequency so that it is more likely to be masked
|
||||
// by the source material.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "adpcm_code.h"
|
||||
|
||||
#define FILTER_LENGTH 15
|
||||
#define WINDOW_LENGTH 101
|
||||
#define MIN_BLOCK_SAMPLES 16
|
||||
|
||||
static void win_average_buffer (float *samples, int sample_count, int half_width);
|
||||
|
||||
// Generate the shaping values for the specified buffer of stereo or mono samples,
|
||||
// one shaping value output for each sample (or stereo pair of samples). This is
|
||||
// calculated by filtering the audio at fs/6 (7350 Hz at 44.1 kHz) and comparing
|
||||
// the averaged levels above and below that frequency. The output shaping values
|
||||
// are nominally in the range of +/-1024, with 1024 indicating first-order HF boost
|
||||
// shaping and -1024 for similar LF boost. However, since -1024 would result in
|
||||
// infinite DC boost (not useful) a "min_value" is passed in. An output value of
|
||||
// zero represents no noise shaping. For stereo input data the channels are summed
|
||||
// for the calculation and the output is still just mono. Note that at the ends of
|
||||
// the buffer the values diverge from true because not all the required source
|
||||
// samples are visible. Use this formula to calculate the number of samples
|
||||
// required for this process to "settle":
|
||||
//
|
||||
// int settle_distance = (WINDOW_LENGTH >> 1) + (FILTER_LENGTH >> 1) + 1;
|
||||
//
|
||||
// We also pass in a "last_value" so that we can smoothly interpolate from that
|
||||
// to the first calculated value during the initial "unknown" samples. This
|
||||
// reduces discontinuities.
|
||||
|
||||
void generate_dns_values (const int16_t *samples, int sample_count, int num_chans, int sample_rate,
|
||||
int16_t *values, int16_t min_value, int16_t last_value)
|
||||
{
|
||||
float dB_offset = 7.3, dB_scaler = 64.0, max_dB, min_dB, max_ratio, min_ratio;
|
||||
int filtered_count = sample_count - FILTER_LENGTH + 1, i;
|
||||
float *low_freq, *high_freq;
|
||||
|
||||
(void) sample_rate; // unused.
|
||||
memset (values, 0, sample_count * sizeof (values [0]));
|
||||
|
||||
if (filtered_count <= 0)
|
||||
return;
|
||||
|
||||
low_freq = malloc (filtered_count * sizeof (float));
|
||||
high_freq = malloc (filtered_count * sizeof (float));
|
||||
|
||||
// First, directly calculate the lowpassed audio using the 15-tap filter. This is
|
||||
// a basic sinc with Hann windowing (for a fast transition) and because the filter
|
||||
// is set to exactly fs/6, some terms are zero (which we can skip). Also, because
|
||||
// it's linear-phase and has an odd number of terms, we can just subtract the LF
|
||||
// result from the original to get the HF values.
|
||||
|
||||
if (num_chans == 1)
|
||||
for (i = 0; i < filtered_count; ++i, ++samples) {
|
||||
float filter_sum =
|
||||
((int32_t) samples [0] + samples [14]) * 0.00150031 +
|
||||
((int32_t) samples [2] + samples [12]) * -0.01703392 +
|
||||
((int32_t) samples [3] + samples [11]) * -0.03449186 +
|
||||
((int32_t) samples [5] + samples [ 9]) * 0.11776258 +
|
||||
((int32_t) samples [6] + samples [ 8]) * 0.26543272 +
|
||||
(int32_t) samples [7] * 0.33366033;
|
||||
|
||||
high_freq [i] = samples [FILTER_LENGTH >> 1] - filter_sum;
|
||||
low_freq [i] = filter_sum;
|
||||
}
|
||||
else
|
||||
for (i = 0; i < filtered_count; ++i, samples += 2) {
|
||||
float filter_sum =
|
||||
((int32_t) samples [ 0] + samples [ 1] + samples [28] + samples [29]) * 0.00150031 +
|
||||
((int32_t) samples [ 4] + samples [ 5] + samples [24] + samples [25]) * -0.01703392 +
|
||||
((int32_t) samples [ 6] + samples [ 7] + samples [22] + samples [23]) * -0.03449186 +
|
||||
((int32_t) samples [10] + samples [11] + samples [18] + samples [19]) * 0.11776258 +
|
||||
((int32_t) samples [12] + samples [13] + samples [16] + samples [17]) * 0.26543272 +
|
||||
((int32_t) samples [14] + samples [15]) * 0.33366033;
|
||||
|
||||
high_freq [i] = samples [FILTER_LENGTH & ~1] + samples [FILTER_LENGTH] - filter_sum;
|
||||
low_freq [i] = filter_sum;
|
||||
}
|
||||
|
||||
// Apply a simple first-order "delta" filter to the lowpass because frequencies below fs/6
|
||||
// become progressively less important for our purposes as the decorrelation filters make
|
||||
// those frequencies less and less relevant. Note that after all this filtering, the
|
||||
// magnitude level of the high frequency array will be 8.7 dB greater than the low frequency
|
||||
// array when the filters are presented with pure white noise (determined empirically).
|
||||
|
||||
for (i = filtered_count - 1; i; --i)
|
||||
low_freq [i] -= low_freq [i - 1];
|
||||
|
||||
low_freq [0] = low_freq [1]; // simply duplicate for the "unknown" sample
|
||||
|
||||
// Next we determine the averaged (absolute) levels for each sample using a box filter.
|
||||
|
||||
win_average_buffer (low_freq, filtered_count, WINDOW_LENGTH >> 1);
|
||||
win_average_buffer (high_freq, filtered_count, WINDOW_LENGTH >> 1);
|
||||
|
||||
// calculate the minimum and maximum ratios that won't be clipped so that we only
|
||||
// have to compute the logarithm when needed
|
||||
|
||||
max_dB = 1024 / dB_scaler - dB_offset;
|
||||
min_dB = min_value / dB_scaler - dB_offset;
|
||||
max_ratio = pow (10.0, max_dB / 20.0);
|
||||
min_ratio = pow (10.0, min_dB / 20.0);
|
||||
|
||||
for (i = 0; i < filtered_count; ++i)
|
||||
if (high_freq [i] > 1.0 && low_freq [i] > 1.0) {
|
||||
float ratio = high_freq [i] / low_freq [i];
|
||||
int shaping_value;
|
||||
|
||||
if (ratio >= max_ratio)
|
||||
shaping_value = 1024;
|
||||
else if (ratio <= min_ratio)
|
||||
shaping_value = min_value;
|
||||
else
|
||||
shaping_value = (int) floor ((log10 (ratio) * 20.0 + dB_offset) * dB_scaler + 0.5);
|
||||
|
||||
values [i + (FILTER_LENGTH >> 1)] = shaping_value;
|
||||
}
|
||||
|
||||
// interpolate the first 7 values from the supplied "last_value" to the first new value
|
||||
|
||||
for (i = 0; i < FILTER_LENGTH >> 1; ++i)
|
||||
values [i] =
|
||||
(
|
||||
(int32_t) values [FILTER_LENGTH >> 1] * (i + 1) +
|
||||
(int32_t) last_value * ((FILTER_LENGTH >> 1) - i) +
|
||||
(FILTER_LENGTH >> 2)
|
||||
) / ((FILTER_LENGTH >> 1) + 1);
|
||||
|
||||
// finally, copy the value at the end into the 7 final positions because unfortunately
|
||||
// we have no "next_value" to interpolate with
|
||||
|
||||
for (i = filtered_count + (FILTER_LENGTH >> 1); i < sample_count; ++i)
|
||||
values [i] = values [(FILTER_LENGTH >> 1) + filtered_count - 1];
|
||||
|
||||
free (low_freq);
|
||||
free (high_freq);
|
||||
}
|
||||
|
||||
// Given a buffer of floating values, apply a simple box filter of specified half width
|
||||
// (total filter width is always odd) to determine the averaged magnitude at each point.
|
||||
// For the ends, we use only the visible samples.
|
||||
|
||||
static void win_average_buffer (float *samples, int sample_count, int half_width)
|
||||
{
|
||||
float *output = malloc (sample_count * sizeof (float));
|
||||
double sum = 0.0;
|
||||
int m = 0, n = 0;
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < sample_count; ++i) {
|
||||
k = i + half_width + 1;
|
||||
j = i - half_width;
|
||||
|
||||
if (k > sample_count) k = sample_count;
|
||||
if (j < 0) j = 0;
|
||||
|
||||
while (m < j) {
|
||||
if ((sum -= samples [m] * samples [m]) < 0.0) sum = 0.0;
|
||||
m++;
|
||||
}
|
||||
|
||||
while (n < k) {
|
||||
sum += samples [n] * samples [n];
|
||||
n++;
|
||||
}
|
||||
|
||||
output [i] = sqrt (sum / (n - m));
|
||||
}
|
||||
|
||||
memcpy (samples, output, sample_count * sizeof (float));
|
||||
free (output);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
#ifndef _INTERCOM_H_
|
||||
#define _INTERCOM_H_
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "osal/task.h"
|
||||
#include "osal/mutex.h"
|
||||
#include "lib/net/eloop/eloop.h"
|
||||
#include "stream_frame.h"
|
||||
#include "ringbuf.h"
|
||||
#include "csi_kernel.h"
|
||||
|
||||
#define iLBC_CODE 0
|
||||
#define OPUS_CODE 0
|
||||
#define ADPCM_CODE 1
|
||||
|
||||
#define FULL_DUPLEX 0
|
||||
#define HALF_DUPLEX 1
|
||||
|
||||
#ifdef PSRAM_HEAP
|
||||
#define intercom_malloc custom_malloc_psram
|
||||
#define intercom_zalloc custom_zalloc_psram
|
||||
#define intercom_free custom_free_psram
|
||||
#else
|
||||
#define intercom_malloc custom_malloc
|
||||
#define intercom_zalloc custom_zalloc
|
||||
#define intercom_free custom_free
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list;
|
||||
uint8* buf_addr;
|
||||
}audio_node;
|
||||
|
||||
#if OPUS_CODE
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list;
|
||||
struct list_head node_head;
|
||||
uint8 seq;
|
||||
uint8 status;
|
||||
uint16 sort;
|
||||
uint32 timestamp;
|
||||
uint32 code_len;
|
||||
uint32 identify_num;
|
||||
uint32 node_cnt;
|
||||
} __attribute__((packed)) sublist;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list;
|
||||
uint8* buf_addr;
|
||||
uint32 data_len;
|
||||
}ringbuf_manage;
|
||||
|
||||
#elif iLBC_CODE || ADPCM_CODE
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list;
|
||||
struct list_head node_head;
|
||||
uint8 seq;
|
||||
uint8 status;
|
||||
uint16 sort;
|
||||
uint32 timestamp;
|
||||
uint32 identify_num;
|
||||
uint32 node_cnt;
|
||||
} __attribute__((packed)) sublist;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head list;
|
||||
uint8* buf_addr;
|
||||
}ringbuf_manage;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SEND_MODE,
|
||||
RECV_MODE
|
||||
}transfer_mode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int udp_sfd;
|
||||
int ack_sfd;
|
||||
int udp_cfd;
|
||||
int ack_cfd;
|
||||
|
||||
struct sockaddr_in udp_s_addr;
|
||||
struct sockaddr_in ack_s_addr;
|
||||
struct sockaddr_in udp_c_addr;
|
||||
struct sockaddr_in ack_c_addr;
|
||||
|
||||
|
||||
#if OPUS_CODE
|
||||
k_task_handle_t recv_task;
|
||||
k_task_handle_t retransfer_task;
|
||||
k_task_handle_t encoded_task;
|
||||
k_task_handle_t decoded_task;
|
||||
k_task_handle_t record_task;
|
||||
#elif iLBC_CODE || ADPCM_CODE
|
||||
struct os_task recv_task;
|
||||
struct os_task retransfer_task;
|
||||
struct os_task encoded_task;
|
||||
struct os_task decoded_task;
|
||||
struct os_task record_task;
|
||||
#endif
|
||||
|
||||
volatile struct list_head srcList_head;
|
||||
volatile struct list_head checkList_head;
|
||||
volatile struct list_head useList_head;
|
||||
|
||||
#if OPUS_CODE
|
||||
char *encoded_task_stack;
|
||||
char *decoded_task_stack;
|
||||
char *recv_task_stack;
|
||||
char *retransfer_task_stack;
|
||||
#endif
|
||||
|
||||
stream *recv_s;
|
||||
stream *send_s;
|
||||
} TYPE_INTERCOM_STRUCT;
|
||||
|
||||
extern TYPE_INTERCOM_STRUCT *intercom;
|
||||
extern void intercom_init(void);
|
||||
void encode_sema_up();
|
||||
void intercom_encode_switch(uint8 enable);
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,402 @@
|
||||
/* 24.May.2005 v.1.0
|
||||
=============================================================================
|
||||
|
||||
U U GGG SSSS TTTTT
|
||||
U U G S T
|
||||
U U G GG SSSS T
|
||||
U U G G S T
|
||||
UUU GG SSS T
|
||||
|
||||
========================================
|
||||
ITU-T - USER'S GROUP ON SOFTWARE TOOLS
|
||||
========================================
|
||||
|
||||
|
||||
=============================================================
|
||||
COPYRIGHT NOTE: This source code, and all of its derivations,
|
||||
is subject to the "ITU-T General Public License". Please have
|
||||
it read in the distribution disk, or in the ITU-T
|
||||
Recommendation G.191 on "SOFTWARE TOOLS FOR SPEECH AND AUDIO
|
||||
CODING STANDARDS".
|
||||
** This code has (C) Copyright by AT&T Corp. **
|
||||
=============================================================
|
||||
|
||||
|
||||
MODULE: G.711 Appendix I PLC module.
|
||||
|
||||
ORIGINAL BY: AT&T Corp.
|
||||
|
||||
FUNCTIONS:
|
||||
|
||||
g711plc_construct: ...... LowcFE Constructor.
|
||||
|
||||
g711plc_dofe: ........... Generate the synthetic signal.
|
||||
At the beginning of an erasure determine the pitch, and extract
|
||||
one pitch period from the tail of the signal. Do an OLA for 1/4
|
||||
of the pitch to smooth the signal. Then repeat the extracted signal
|
||||
for the length of the erasure. If the erasure continues for more than
|
||||
10 msec, increase the number of periods in the pitchbuffer. At the end
|
||||
of an erasure, do an OLA with the start of the first good frame.
|
||||
The gain decays as the erasure gets longer.
|
||||
|
||||
g711plc_addtohistory: ... A good frame was received and decoded.
|
||||
If right after an erasure, do an overlap add with the synthetic signal.
|
||||
Add the frame to history buffer.
|
||||
|
||||
HISTORY:
|
||||
|
||||
24.May.05 v1.0 Release of 1st G711 PLC module <AT&T>.
|
||||
Integration of this module in STL2005 <Cyril Guillaume & Stephane Ragot - stephane.ragot@francetelecom.com>.
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "lowcfe.h"
|
||||
|
||||
static void g711plc_scalespeech(LowcFE_c*, short *out);
|
||||
static void g711plc_getfespeech(LowcFE_c*, short *out, int sz);
|
||||
static void g711plc_savespeech(LowcFE_c*, short *s);
|
||||
static int g711plc_findpitch(LowcFE_c*);
|
||||
static int findpitch_amdf(LowcFE_c *lc);
|
||||
static void g711plc_overlapadd(Float *l, Float *r, Float *o, int cnt);
|
||||
static void g711plc_overlapadds(short *l, short *r, short *o, int cnt);
|
||||
static void g711plc_overlapaddatend(LowcFE_c*, short *s, short *f, int cnt);
|
||||
static void g711plc_convertsf(short *f, Float *t, int cnt);
|
||||
static void g711plc_convertfs(Float *f, short *t, int cnt);
|
||||
static void g711plc_copyf(Float *f, Float *t, int cnt);
|
||||
static void g711plc_copys(short *f, short *t, int cnt);
|
||||
static void g711plc_zeros(short *s, int cnt);
|
||||
|
||||
void g711plc_construct(LowcFE_c *lc)
|
||||
{
|
||||
lc->erasecnt = 0;
|
||||
lc->pitchbufend = &lc->pitchbuf[HISTORYLEN];
|
||||
g711plc_zeros(lc->history, HISTORYLEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get samples from the circular pitch buffer. Update poffset so
|
||||
* when subsequent frames are erased the signal continues.
|
||||
*/
|
||||
static void g711plc_getfespeech(LowcFE_c *lc, short *out, int sz)
|
||||
{
|
||||
while (sz) {
|
||||
int cnt = lc->pitchblen - lc->poffset;
|
||||
if (cnt > sz)
|
||||
cnt = sz;
|
||||
g711plc_copys(&lc->pitchbufstart[lc->poffset], out, cnt);
|
||||
lc->poffset += cnt;
|
||||
if (lc->poffset == lc->pitchblen)
|
||||
lc->poffset = 0;
|
||||
out += cnt;
|
||||
sz -= cnt;
|
||||
}
|
||||
}
|
||||
|
||||
static void g711plc_scalespeech(LowcFE_c *lc, short *out)
|
||||
{
|
||||
int i;
|
||||
Float g = (Float)1. - (lc->erasecnt - 1) * ATTENFAC;
|
||||
for (i = 0; i < FRAMESZ; i++) {
|
||||
out[i] = (short)(out[i] * g);
|
||||
g -= ATTENINCR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the synthetic signal.
|
||||
* At the beginning of an erasure determine the pitch, and extract
|
||||
* one pitch period from the tail of the signal. Do an OLA for 1/4
|
||||
* of the pitch to smooth the signal. Then repeat the extracted signal
|
||||
* for the length of the erasure. If the erasure continues for more than
|
||||
* 10 msec, increase the number of periods in the pitchbuffer. At the end
|
||||
* of an erasure, do an OLA with the start of the first good frame.
|
||||
* The gain decays as the erasure gets longer.
|
||||
*/
|
||||
void g711plc_dofe(LowcFE_c *lc,short *out)
|
||||
{
|
||||
if (lc->erasecnt == 0) {
|
||||
/* get history */
|
||||
g711plc_copys(lc->history, lc->pitchbuf, HISTORYLEN);
|
||||
lc->pitch = g711plc_findpitch(lc); /* find pitch */
|
||||
lc->poverlap = lc->pitch >> 2; /* OLA 1/4 wavelength */
|
||||
/* save original last poverlap samples */
|
||||
g711plc_copys(lc->pitchbufend - lc->poverlap, lc->lastq,
|
||||
lc->poverlap);
|
||||
lc->poffset = 0; /* create pitch buffer with 1 period */
|
||||
lc->pitchblen = lc->pitch;
|
||||
lc->pitchbufstart = lc->pitchbufend - lc->pitchblen;
|
||||
g711plc_overlapadds(lc->lastq, lc->pitchbufstart - lc->poverlap,
|
||||
lc->pitchbufend - lc->poverlap, lc->poverlap);
|
||||
/* update last 1/4 wavelength in history buffer */
|
||||
g711plc_copys(lc->pitchbufend - lc->poverlap,
|
||||
&lc->history[HISTORYLEN-lc->poverlap], lc->poverlap);
|
||||
/* get synthesized speech */
|
||||
g711plc_getfespeech(lc, out, FRAMESZ);
|
||||
} else if (lc->erasecnt == 1 || lc->erasecnt == 2) {
|
||||
/* tail of previous pitch estimate */
|
||||
short tmp[POVERLAPMAX];
|
||||
int saveoffset = lc->poffset; /* save offset for OLA */
|
||||
/* continue with old pitchbuf */
|
||||
g711plc_getfespeech(lc, tmp, lc->poverlap);
|
||||
/* add periods to the pitch buffer */
|
||||
lc->poffset = saveoffset;
|
||||
while (lc->poffset > lc->pitch)
|
||||
lc->poffset -= lc->pitch;
|
||||
lc->pitchblen += lc->pitch; /* add a period */
|
||||
lc->pitchbufstart = lc->pitchbufend - lc->pitchblen;
|
||||
g711plc_overlapadds(lc->lastq, lc->pitchbufstart - lc->poverlap,
|
||||
lc->pitchbufend - lc->poverlap, lc->poverlap);
|
||||
/* overlap add old pitchbuffer with new */
|
||||
g711plc_getfespeech(lc, out, FRAMESZ);
|
||||
g711plc_overlapadds(tmp, out, out, lc->poverlap);
|
||||
g711plc_scalespeech(lc, out);
|
||||
} else if (lc->erasecnt > 2) {
|
||||
g711plc_zeros(out, FRAMESZ);
|
||||
} else {
|
||||
g711plc_getfespeech(lc, out, FRAMESZ);
|
||||
g711plc_scalespeech(lc, out);
|
||||
}
|
||||
lc->erasecnt++;
|
||||
g711plc_savespeech(lc, out);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save a frames worth of new speech in the history buffer.
|
||||
* Return the output speech delayed by POVERLAPMAX.
|
||||
*/
|
||||
static void g711plc_savespeech(LowcFE_c *lc, short *s)
|
||||
{
|
||||
/* make room for new signal */
|
||||
g711plc_copys(&lc->history[FRAMESZ], lc->history, HISTORYLEN - FRAMESZ);
|
||||
/* copy in the new frame */
|
||||
g711plc_copys(s, &lc->history[HISTORYLEN - FRAMESZ], FRAMESZ);
|
||||
/* copy out the delayed frame */
|
||||
g711plc_copys(&lc->history[HISTORYLEN - FRAMESZ - POVERLAPMAX], s,
|
||||
FRAMESZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* A good frame was received and decoded.
|
||||
* If right after an erasure, do an overlap add with the synthetic signal.
|
||||
* Add the frame to history buffer.
|
||||
*/
|
||||
void g711plc_addtohistory(LowcFE_c *lc, short *s)
|
||||
{
|
||||
if (lc->erasecnt) {
|
||||
short overlapbuf[FRAMESZ];
|
||||
/*
|
||||
* longer erasures require longer overlaps
|
||||
* to smooth the transition between the synthetic
|
||||
* and real signal.
|
||||
*/
|
||||
int olen = lc->poverlap + (lc->erasecnt - 1) * EOVERLAPINCR;
|
||||
if (olen > FRAMESZ)
|
||||
olen = FRAMESZ;
|
||||
g711plc_getfespeech(lc, overlapbuf, olen);
|
||||
g711plc_overlapaddatend(lc, s, overlapbuf, olen);
|
||||
lc->erasecnt = 0;
|
||||
}
|
||||
g711plc_savespeech(lc, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overlapp add the end of the erasure with the start of the first good frame
|
||||
* Scale the synthetic speech by the gain factor before the OLA.
|
||||
*/
|
||||
static void g711plc_overlapaddatend(LowcFE_c *lc, short *s, short *f, int cnt)
|
||||
{
|
||||
int i;
|
||||
Float incrg;
|
||||
Float lw, rw;
|
||||
Float t;
|
||||
Float incr = (Float)1. / cnt;
|
||||
Float gain = (Float)1. - (lc->erasecnt - 1) * ATTENFAC;
|
||||
if (gain < 0.)
|
||||
gain = (Float)0.;
|
||||
incrg = incr * gain;
|
||||
lw = ((Float)1. - incr) * gain;
|
||||
rw = incr;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
t = lw * f[i] + rw * s[i];
|
||||
if (t > 32767.)
|
||||
t = (Float)32767.;
|
||||
else if (t < -32768.)
|
||||
t = (Float)-32768.;
|
||||
s[i] = (short)t;
|
||||
lw -= incrg;
|
||||
rw += incr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Overlapp add left and right sides
|
||||
*/
|
||||
static void g711plc_overlapadd(Float *l, Float *r, Float *o, int cnt)
|
||||
{
|
||||
int i;
|
||||
Float incr, lw, rw, t;
|
||||
|
||||
if (cnt == 0)
|
||||
return;
|
||||
incr = (Float)1. / cnt;
|
||||
lw = (Float)1. - incr;
|
||||
rw = incr;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
t = lw * l[i] + rw * r[i];
|
||||
if (t > (Float)32767.)
|
||||
t = (Float)32767.;
|
||||
else if (t < (Float)-32768.)
|
||||
t = (Float)-32768.;
|
||||
o[i] = t;
|
||||
lw -= incr;
|
||||
rw += incr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Overlapp add left and right sides
|
||||
*/
|
||||
static void g711plc_overlapadds(short *l, short *r, short *o, int cnt)
|
||||
{
|
||||
int i;
|
||||
Float incr, lw, rw, t;
|
||||
|
||||
if (cnt == 0)
|
||||
return;
|
||||
incr = (Float)1. / cnt;
|
||||
lw = (Float)1. - incr;
|
||||
rw = incr;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
t = lw * l[i] + rw * r[i];
|
||||
if (t > (Float)32767.)
|
||||
t = (Float)32767.;
|
||||
else if (t < (Float)-32768.)
|
||||
t = (Float)-32768.;
|
||||
o[i] = (short)t;
|
||||
lw -= incr;
|
||||
rw += incr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Estimate the pitch.
|
||||
* l - pointer to first sample in last 20 msec of speech.
|
||||
* r - points to the sample PITCH_MAX before l
|
||||
*/
|
||||
static int g711plc_findpitch(LowcFE_c *lc)
|
||||
{
|
||||
int i, j, k;
|
||||
int bestmatch;
|
||||
int bestcorr;
|
||||
int corr; /* correlation */
|
||||
unsigned int energy; /* running energy */
|
||||
unsigned int scale; /* scale correlation by average power */
|
||||
short *rp; /* segment to match */
|
||||
short *l = lc->pitchbufend - CORRLEN;
|
||||
short *r = lc->pitchbufend - CORRBUFLEN;
|
||||
|
||||
/* coarse search */
|
||||
rp = r;
|
||||
energy = 0;
|
||||
corr = 0;
|
||||
for (i = 0; i < CORRLEN; i += NDEC) {
|
||||
energy += rp[i] * rp[i];
|
||||
corr += rp[i] * l[i];
|
||||
}
|
||||
scale = energy;
|
||||
if (scale < CORRMINPOWER)
|
||||
scale = CORRMINPOWER;
|
||||
corr = corr / sqrt(scale);
|
||||
bestcorr = corr;
|
||||
bestmatch = 0;
|
||||
for (j = NDEC; j <= PITCHDIFF; j += NDEC) {
|
||||
energy -= rp[0] * rp[0];
|
||||
energy += rp[CORRLEN] * rp[CORRLEN];
|
||||
rp += NDEC;
|
||||
corr = 0;
|
||||
for (i = 0; i < CORRLEN; i += NDEC)
|
||||
corr += rp[i] * l[i];
|
||||
scale = energy;
|
||||
if (scale < CORRMINPOWER)
|
||||
scale = CORRMINPOWER;
|
||||
corr /= sqrt(scale);
|
||||
if (corr >= bestcorr) {
|
||||
bestcorr = corr;
|
||||
bestmatch = j;
|
||||
}
|
||||
}
|
||||
/* fine search */
|
||||
j = bestmatch - (NDEC - 1);
|
||||
if (j < 0)
|
||||
j = 0;
|
||||
k = bestmatch + (NDEC - 1);
|
||||
if (k > PITCHDIFF)
|
||||
k = PITCHDIFF;
|
||||
rp = &r[j];
|
||||
energy = 0;
|
||||
corr = 0;
|
||||
for (i = 0; i < CORRLEN; i++) {
|
||||
energy += rp[i] * rp[i];
|
||||
corr += rp[i] * l[i];
|
||||
}
|
||||
scale = energy;
|
||||
if (scale < CORRMINPOWER)
|
||||
scale = CORRMINPOWER;
|
||||
corr = corr / sqrt(scale);
|
||||
bestcorr = corr;
|
||||
bestmatch = j;
|
||||
for (j++; j <= k; j++) {
|
||||
energy -= rp[0] * rp[0];
|
||||
energy += rp[CORRLEN] * rp[CORRLEN];
|
||||
rp++;
|
||||
corr = 0;
|
||||
for (i = 0; i < CORRLEN; i++)
|
||||
corr += rp[i] * l[i];
|
||||
scale = energy;
|
||||
if (scale < CORRMINPOWER)
|
||||
scale = CORRMINPOWER;
|
||||
corr = corr / sqrt(scale);
|
||||
if (corr > bestcorr) {
|
||||
bestcorr = corr;
|
||||
bestmatch = j;
|
||||
}
|
||||
}
|
||||
return PITCH_MAX - bestmatch;
|
||||
}
|
||||
|
||||
static void g711plc_convertsf(short *f, Float *t, int cnt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cnt; i++)
|
||||
t[i] = (Float)f[i];
|
||||
}
|
||||
|
||||
static void g711plc_convertfs(Float *f, short *t, int cnt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cnt; i++)
|
||||
t[i] = (short)f[i];
|
||||
}
|
||||
|
||||
static void g711plc_copyf(Float *f, Float *t, int cnt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cnt; i++)
|
||||
t[i] = f[i];
|
||||
}
|
||||
|
||||
static void g711plc_copys(short *f, short *t, int cnt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cnt; i++)
|
||||
t[i] = f[i];
|
||||
}
|
||||
|
||||
static void g711plc_zeros(short *s, int cnt)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cnt; i++)
|
||||
s[i] = 0;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
============================================================================
|
||||
File: lowcfe.h V.1.0-24.MAY-2005
|
||||
============================================================================
|
||||
|
||||
UGST/ITU-T G711 Appendix I PLC MODULE
|
||||
|
||||
GLOBAL FUNCTION PROTOTYPES
|
||||
|
||||
History:
|
||||
24.May.05 v1.0 First version <AT&T>
|
||||
Integration in STL2005 <Cyril Guillaume & Stephane Ragot - stephane.ragot@francetelecom.com>
|
||||
============================================================================
|
||||
*/
|
||||
#ifndef __LOWCFE_C_H__
|
||||
#define __LOWCFE_C_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef USEDOUBLES
|
||||
typedef double Float; /* likely to be bit-exact between machines */
|
||||
#else
|
||||
typedef float Float;
|
||||
#endif
|
||||
|
||||
#define PITCH_MIN 40 /* minimum allowed pitch, 200 Hz */
|
||||
#define PITCH_MAX 120 /* maximum allowed pitch, 66 Hz */
|
||||
#define PITCHDIFF (PITCH_MAX - PITCH_MIN)
|
||||
#define POVERLAPMAX (PITCH_MAX >> 2)/* maximum pitch OLA window */
|
||||
#define HISTORYLEN (PITCH_MAX * 3 + POVERLAPMAX) /* history buffer length*/
|
||||
#define NDEC 2 /* 2:1 decimation */
|
||||
#define CORRLEN 160 /* 20 msec correlation length */
|
||||
#define CORRBUFLEN (CORRLEN + PITCH_MAX) /* correlation buffer length */
|
||||
#define CORRMINPOWER (250) /* minimum power */
|
||||
#define EOVERLAPINCR 32 /* end OLA increment per frame, 4ms */
|
||||
#define FRAMESZ 80 /* 10 msec at 8kHz */
|
||||
#define ATTENFAC ((Float).2) /* attenuation factor per 10ms frame */
|
||||
#define ATTENINCR (ATTENFAC/FRAMESZ) /* attenuation per sample */
|
||||
|
||||
typedef struct _LowcFE_c {
|
||||
int erasecnt; /* consecutive erased frames */
|
||||
int poverlap; /* overlap based on pitch */
|
||||
int poffset; /* offset into pitch period */
|
||||
int pitch; /* pitch estimate */
|
||||
int pitchblen; /* current pitch buffer length */
|
||||
short *pitchbufend; /* end of pitch buffer */
|
||||
short *pitchbufstart; /* start of pitch buffer */
|
||||
short pitchbuf[HISTORYLEN]; /* buffer for cycles of speech */
|
||||
short lastq[POVERLAPMAX]; /* saved last quarter wavelengh */
|
||||
short history[HISTORYLEN]; /* history buffer */
|
||||
} LowcFE_c;
|
||||
|
||||
/* public functions */
|
||||
void g711plc_construct(LowcFE_c*); /* constructor */
|
||||
void g711plc_dofe(LowcFE_c*, short *s); /* synthesize speech for erasure */
|
||||
void g711plc_addtohistory(LowcFE_c*, short *s);
|
||||
/* add a good frame to history buffer */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LOWCFE_C_H__ */
|
||||
@@ -0,0 +1,107 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "ringbuf.h"
|
||||
#include "osal/string.h"
|
||||
#include "custom_mem/custom_mem.h"
|
||||
|
||||
int ringbuf_Init(TYPE_RINGBUF *buf, unsigned int buf_size)
|
||||
{
|
||||
if(buf == NULL) {
|
||||
printf("Fail to init ringbuf!\r\n");
|
||||
return -1;
|
||||
}
|
||||
buf->front = 0;
|
||||
buf->rear = 0;
|
||||
buf->size = buf_size;
|
||||
printf("create ringbuf succes,size:%d\n",buf->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int push_ringbuf(TYPE_RINGBUF *buf, void *data, unsigned int len)
|
||||
{
|
||||
if(buf->data == NULL) {
|
||||
printf("Push ringbuf err!\r\n");
|
||||
return -1;
|
||||
}
|
||||
if( (buf->rear + len) > (buf->size))
|
||||
{
|
||||
os_memcpy( (buf->data + buf->rear), data, (buf->size - buf->rear));
|
||||
os_memcpy( buf->data, (data+(buf->size - buf->rear)), (len - buf->size + buf->rear));
|
||||
}
|
||||
else
|
||||
os_memcpy( buf->data + buf->rear, data, len);
|
||||
buf->rear = (buf->rear+len)%(buf->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pop_ringbuf(TYPE_RINGBUF *buf, void *data, unsigned int len)
|
||||
{
|
||||
if(buf->data == NULL) {
|
||||
printf("Pop ringbuf err!!\r\n");
|
||||
return -1;
|
||||
}
|
||||
if(buf->front == buf->rear) {
|
||||
printf("Ringbuf is empty!\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( (buf->front + len) > (buf->size) )
|
||||
{
|
||||
os_memcpy( data, (buf->data + buf->front), (buf->size - buf->front));
|
||||
os_memcpy( (data+(buf->size - buf->front)), buf->data, (len - buf->size + buf->front));
|
||||
}
|
||||
else
|
||||
os_memcpy(data, (buf->data + buf->front), len);
|
||||
buf->front = (buf->front+len)%(buf->size);
|
||||
return 0;
|
||||
}
|
||||
int pop_ringbuf_notmove(TYPE_RINGBUF *buf, void *data, unsigned int len)
|
||||
{
|
||||
if(buf->data == NULL) {
|
||||
printf("Pop ringbuf err!!\r\n");
|
||||
return -1;
|
||||
}
|
||||
if(buf->front == buf->rear) {
|
||||
printf("Ringbuf is empty!\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( (buf->front + len) > (buf->size) )
|
||||
{
|
||||
os_memcpy( data, (buf->data + buf->front), (buf->size - buf->front));
|
||||
os_memcpy( (data+(buf->size - buf->front)), buf->data, (len - buf->size + buf->front));
|
||||
}
|
||||
else
|
||||
os_memcpy(data, (buf->data + buf->front), len);
|
||||
return 0;
|
||||
}
|
||||
int ringbuf_pop_available(TYPE_RINGBUF *buf)
|
||||
{
|
||||
if(buf == NULL) {
|
||||
printf(" Get ringbuf available err!\r\n");
|
||||
return -1;
|
||||
}
|
||||
return ( ((buf->rear+buf->size)-buf->front) % (buf->size) );
|
||||
}
|
||||
int ringbuf_push_available(TYPE_RINGBUF *buf)
|
||||
{
|
||||
if(buf == NULL) {
|
||||
printf(" Get ringbuf available err!\r\n");
|
||||
return -1;
|
||||
}
|
||||
return ( ((buf->front+buf->size)-buf->rear-1) % (buf->size) );
|
||||
}
|
||||
int ringbuf_del(TYPE_RINGBUF *buf)
|
||||
{
|
||||
if(buf == NULL) {
|
||||
printf("Ringbuf del err!\r\n");
|
||||
return -1;
|
||||
}
|
||||
#ifdef PSRAM_HEAP
|
||||
custom_free_psram(buf);
|
||||
#else
|
||||
custom_free(buf);
|
||||
#endif
|
||||
buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef __RINGBUF_H
|
||||
#define __RINGBUF_H
|
||||
|
||||
typedef struct ringbuf {
|
||||
void *data;
|
||||
volatile unsigned int front;
|
||||
volatile unsigned int rear;
|
||||
volatile unsigned int size;
|
||||
} TYPE_RINGBUF;
|
||||
|
||||
extern int ringbuf_Init(TYPE_RINGBUF *buf, unsigned int buf_size);
|
||||
extern int push_ringbuf(TYPE_RINGBUF *buf, void *data, unsigned int len);
|
||||
extern int pop_ringbuf(TYPE_RINGBUF *buf, void *data, unsigned int len);
|
||||
extern int pop_ringbuf_notmove(TYPE_RINGBUF *buf, void *data, unsigned int len);
|
||||
extern int ringbuf_pop_available(TYPE_RINGBUF *buf);
|
||||
extern int ringbuf_push_available(TYPE_RINGBUF *buf);
|
||||
extern int ringbuf_del(TYPE_RINGBUF *buf);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user