Asterisk - The Open Source Telephony Project GIT-master-7e7a603
plc.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Written by Steve Underwood <steveu@coppice.org>
5 *
6 * Copyright (C) 2004 Steve Underwood
7 *
8 * All rights reserved.
9 *
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
15 *
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
19 *
20 * This version may be optionally licenced under the GNU LGPL licence.
21 *
22 * A license has been granted to Digium (via disclaimer) for the use of
23 * this code.
24 */
25
26/*! \file
27 *
28 * \brief SpanDSP - a series of DSP components for telephony
29 *
30 * \author Steve Underwood <steveu@coppice.org>
31 */
32
33/*** MODULEINFO
34 <support_level>core</support_level>
35 ***/
36
37#include "asterisk.h"
38
39#include <math.h>
40
41#include "asterisk/config.h"
42#include "asterisk/module.h"
43#include "asterisk/plc.h"
44
45#if !defined(FALSE)
46#define FALSE 0
47#endif
48#if !defined(TRUE)
49#define TRUE (!FALSE)
50#endif
51
52#if !defined(INT16_MAX)
53#define INT16_MAX (32767)
54#define INT16_MIN (-32767-1)
55#endif
56
57/* We do a straight line fade to zero volume in 50ms when we are filling in for missing data. */
58#define ATTENUATION_INCREMENT 0.0025 /* Attenuation per sample */
59
60#define ms_to_samples(t) (((t)*DEFAULT_SAMPLE_RATE)/1000)
61
62static inline int16_t fsaturate(double damp)
63{
64 if (damp > 32767.0)
65 return INT16_MAX;
66 if (damp < -32768.0)
67 return INT16_MIN;
68 return (int16_t) rint(damp);
69}
70
71static void save_history(plc_state_t *s, int16_t *buf, int len)
72{
73 if (len >= PLC_HISTORY_LEN) {
74 /* Just keep the last part of the new data, starting at the beginning of the buffer */
75 memcpy(s->history, buf + len - PLC_HISTORY_LEN, sizeof(int16_t) * PLC_HISTORY_LEN);
76 s->buf_ptr = 0;
77 return;
78 }
79 if (s->buf_ptr + len > PLC_HISTORY_LEN) {
80 /* Wraps around - must break into two sections */
81 memcpy(s->history + s->buf_ptr, buf, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr));
82 len -= (PLC_HISTORY_LEN - s->buf_ptr);
83 memcpy(s->history, buf + (PLC_HISTORY_LEN - s->buf_ptr), sizeof(int16_t)*len);
84 s->buf_ptr = len;
85 return;
86 }
87 /* Can use just one section */
88 memcpy(s->history + s->buf_ptr, buf, sizeof(int16_t)*len);
89 s->buf_ptr += len;
90}
91
92/*- End of function --------------------------------------------------------*/
93
95{
97
98 if (s->buf_ptr == 0)
99 return;
100 memcpy(tmp, s->history, sizeof(int16_t)*s->buf_ptr);
101 memmove(s->history, s->history + s->buf_ptr, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr));
102 memcpy(s->history + PLC_HISTORY_LEN - s->buf_ptr, tmp, sizeof(int16_t) * s->buf_ptr);
103 s->buf_ptr = 0;
104}
105
106/*- End of function --------------------------------------------------------*/
107
108static int __inline__ amdf_pitch(int min_pitch, int max_pitch, int16_t amp[], int len)
109{
110 int i;
111 int j;
112 int acc;
113 int min_acc;
114 int pitch;
115
116 pitch = min_pitch;
117 min_acc = INT_MAX;
118 for (i = max_pitch; i <= min_pitch; i++) {
119 acc = 0;
120 for (j = 0; j < len; j++)
121 acc += abs(amp[i + j] - amp[j]);
122 if (acc < min_acc) {
123 min_acc = acc;
124 pitch = i;
125 }
126 }
127 return pitch;
128}
129
130/*- End of function --------------------------------------------------------*/
131
132int plc_rx(plc_state_t *s, int16_t amp[], int len)
133{
134 int i;
135 int pitch_overlap;
136 float old_step;
137 float new_step;
138 float old_weight;
139 float new_weight;
140 float gain;
141
142 if (s->missing_samples) {
143 /* Although we have a real signal, we need to smooth it to fit well
144 with the synthetic signal we used for the previous block */
145
146 /* The start of the real data is overlapped with the next 1/4 cycle
147 of the synthetic data. */
148 pitch_overlap = s->pitch >> 2;
149 if (pitch_overlap > len)
150 pitch_overlap = len;
152 if (gain < 0.0)
153 gain = 0.0;
154 new_step = 1.0/pitch_overlap;
155 old_step = new_step*gain;
156 new_weight = new_step;
157 old_weight = (1.0 - new_step)*gain;
158 for (i = 0; i < pitch_overlap; i++) {
159 amp[i] = fsaturate(old_weight * s->pitchbuf[s->pitch_offset] + new_weight * amp[i]);
160 if (++s->pitch_offset >= s->pitch)
161 s->pitch_offset = 0;
162 new_weight += new_step;
163 old_weight -= old_step;
164 if (old_weight < 0.0)
165 old_weight = 0.0;
166 }
167 s->missing_samples = 0;
168 }
169 save_history(s, amp, len);
170 return len;
171}
172
173/*- End of function --------------------------------------------------------*/
174
176{
177 int i;
178 int pitch_overlap;
179 float old_step;
180 float new_step;
181 float old_weight;
182 float new_weight;
183 float gain;
184 int orig_len;
185
186 orig_len = len;
187 if (s->missing_samples == 0) {
188 /* As the gap in real speech starts we need to assess the last known pitch,
189 and prepare the synthetic data we will use for fill-in */
192 /* We overlap a 1/4 wavelength */
193 pitch_overlap = s->pitch >> 2;
194 /* Cook up a single cycle of pitch, using a single of the real signal with 1/4
195 cycle OLA'ed to make the ends join up nicely */
196 /* The first 3/4 of the cycle is a simple copy */
197 for (i = 0; i < s->pitch - pitch_overlap; i++)
198 s->pitchbuf[i] = s->history[PLC_HISTORY_LEN - s->pitch + i];
199 /* The last 1/4 of the cycle is overlapped with the end of the previous cycle */
200 new_step = 1.0/pitch_overlap;
201 new_weight = new_step;
202 for ( ; i < s->pitch; i++) {
203 s->pitchbuf[i] = s->history[PLC_HISTORY_LEN - s->pitch + i] * (1.0 - new_weight) + s->history[PLC_HISTORY_LEN - 2 * s->pitch + i]*new_weight;
204 new_weight += new_step;
205 }
206 /* We should now be ready to fill in the gap with repeated, decaying cycles
207 of what is in pitchbuf */
208
209 /* We need to OLA the first 1/4 wavelength of the synthetic data, to smooth
210 it into the previous real data. To avoid the need to introduce a delay
211 in the stream, reverse the last 1/4 wavelength, and OLA with that. */
212 gain = 1.0;
213 new_step = 1.0 / pitch_overlap;
214 old_step = new_step;
215 new_weight = new_step;
216 old_weight = 1.0 - new_step;
217 for (i = 0; i < pitch_overlap; i++) {
218 amp[i] = fsaturate(old_weight * s->history[PLC_HISTORY_LEN - 1 - i] + new_weight * s->pitchbuf[i]);
219 new_weight += new_step;
220 old_weight -= old_step;
221 if (old_weight < 0.0)
222 old_weight = 0.0;
223 }
224 s->pitch_offset = i;
225 } else {
227 i = 0;
228 }
229 for ( ; gain > 0.0 && i < len; i++) {
230 amp[i] = s->pitchbuf[s->pitch_offset] * gain;
231 gain -= ATTENUATION_INCREMENT;
232 if (++s->pitch_offset >= s->pitch)
233 s->pitch_offset = 0;
234 }
235 for ( ; i < len; i++)
236 amp[i] = 0;
237 s->missing_samples += orig_len;
238 save_history(s, amp, len);
239 return len;
240}
241
242/*- End of function --------------------------------------------------------*/
243
245{
246 memset(s, 0, sizeof(*s));
247 return s;
248}
249/*- End of function --------------------------------------------------------*/
250/*- End of file ------------------------------------------------------------*/
251
252static int reload_module(void)
253{
254 struct ast_variable *var;
255 struct ast_flags config_flags = { 0 };
256 struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
257
259 return 0;
260 }
261
262 for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
263 if (!strcasecmp(var->name, "genericplc")) {
265 } else if (!strcasecmp(var->name, "genericplc_on_equal_codecs")) {
267 }
268 }
270
271 /*
272 * Force on_equal_codecs to false if generic_plc is false.
273 */
274 if (!ast_opt_generic_plc) {
276 }
277
278 return 0;
279}
280
281static int load_module(void)
282{
284
286}
287
288static int unload_module(void)
289{
290 return 0;
291}
292
294 .support_level = AST_MODULE_SUPPORT_CORE,
295 .load = load_module,
296 .unload = unload_module,
298 .load_pri = AST_MODPRI_CORE,
299 .requires = "extconfig",
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
static int tmp()
Definition: bt_open.c:389
short int16_t
Definition: db.h:59
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define abs(x)
Definition: f2c.h:195
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct ast_flags ast_options
Definition: options.c:61
@ AST_OPT_FLAG_GENERIC_PLC
Definition: options.h:100
@ AST_OPT_FLAG_GENERIC_PLC_ON_EQUAL_CODECS
Definition: options.h:102
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEMISSING
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_CORE
Definition: module.h:324
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
#define ast_opt_generic_plc
Definition: options.h:134
int plc_fillin(plc_state_t *s, int16_t amp[], int len)
Fill-in a block of missing audio samples.
Definition: plc.c:175
static void normalise_history(plc_state_t *s)
Definition: plc.c:94
static int reload_module(void)
Definition: plc.c:252
static int __inline__ amdf_pitch(int min_pitch, int max_pitch, int16_t amp[], int len)
Definition: plc.c:108
static int16_t fsaturate(double damp)
Definition: plc.c:62
static void save_history(plc_state_t *s, int16_t *buf, int len)
Definition: plc.c:71
plc_state_t * plc_init(plc_state_t *s)
Process a block of received V.29 modem audio samples.
Definition: plc.c:244
static int load_module(void)
Definition: plc.c:281
#define INT16_MAX
Definition: plc.c:53
static int unload_module(void)
Definition: plc.c:288
#define INT16_MIN
Definition: plc.c:54
#define ATTENUATION_INCREMENT
Definition: plc.c:58
int plc_rx(plc_state_t *s, int16_t amp[], int len)
Process a block of received audio samples.
Definition: plc.c:132
SpanDSP - a series of DSP components for telephony.
#define CORRELATION_SPAN
Definition: plc.h:99
#define PLC_HISTORY_LEN
Definition: plc.h:103
#define PLC_PITCH_MIN
Definition: plc.h:93
#define PLC_PITCH_MAX
Definition: plc.h:95
static int reload(void)
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
Structure used to handle boolean flags.
Definition: utils.h:199
Structure for variables, used for configurations and for channel variables.
int pitch_offset
Definition: plc.h:110
int pitch
Definition: plc.h:112
int16_t history[PLC_HISTORY_LEN]
Definition: plc.h:116
float pitchbuf[PLC_PITCH_MIN]
Definition: plc.h:114
int missing_samples
Definition: plc.h:108
int buf_ptr
Definition: plc.h:118
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94