plc.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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. /*! \file
  26. *
  27. * \brief SpanDSP - a series of DSP components for telephony
  28. *
  29. * \author Steve Underwood <steveu@coppice.org>
  30. */
  31. /*** MODULEINFO
  32. <support_level>core</support_level>
  33. ***/
  34. #include "asterisk.h"
  35. #include <math.h>
  36. #include "asterisk/config.h"
  37. #include "asterisk/module.h"
  38. #include "asterisk/plc.h"
  39. #if !defined(FALSE)
  40. #define FALSE 0
  41. #endif
  42. #if !defined(TRUE)
  43. #define TRUE (!FALSE)
  44. #endif
  45. #if !defined(INT16_MAX)
  46. #define INT16_MAX (32767)
  47. #define INT16_MIN (-32767-1)
  48. #endif
  49. /* We do a straight line fade to zero volume in 50ms when we are filling in for missing data. */
  50. #define ATTENUATION_INCREMENT 0.0025 /* Attenuation per sample */
  51. #define ms_to_samples(t) (((t)*DEFAULT_SAMPLE_RATE)/1000)
  52. static inline int16_t fsaturate(double damp)
  53. {
  54. if (damp > 32767.0)
  55. return INT16_MAX;
  56. if (damp < -32768.0)
  57. return INT16_MIN;
  58. return (int16_t) rint(damp);
  59. }
  60. static void save_history(plc_state_t *s, int16_t *buf, int len)
  61. {
  62. if (len >= PLC_HISTORY_LEN) {
  63. /* Just keep the last part of the new data, starting at the beginning of the buffer */
  64. memcpy(s->history, buf + len - PLC_HISTORY_LEN, sizeof(int16_t) * PLC_HISTORY_LEN);
  65. s->buf_ptr = 0;
  66. return;
  67. }
  68. if (s->buf_ptr + len > PLC_HISTORY_LEN) {
  69. /* Wraps around - must break into two sections */
  70. memcpy(s->history + s->buf_ptr, buf, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr));
  71. len -= (PLC_HISTORY_LEN - s->buf_ptr);
  72. memcpy(s->history, buf + (PLC_HISTORY_LEN - s->buf_ptr), sizeof(int16_t)*len);
  73. s->buf_ptr = len;
  74. return;
  75. }
  76. /* Can use just one section */
  77. memcpy(s->history + s->buf_ptr, buf, sizeof(int16_t)*len);
  78. s->buf_ptr += len;
  79. }
  80. /*- End of function --------------------------------------------------------*/
  81. static void normalise_history(plc_state_t *s)
  82. {
  83. int16_t tmp[PLC_HISTORY_LEN];
  84. if (s->buf_ptr == 0)
  85. return;
  86. memcpy(tmp, s->history, sizeof(int16_t)*s->buf_ptr);
  87. memmove(s->history, s->history + s->buf_ptr, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr));
  88. memcpy(s->history + PLC_HISTORY_LEN - s->buf_ptr, tmp, sizeof(int16_t) * s->buf_ptr);
  89. s->buf_ptr = 0;
  90. }
  91. /*- End of function --------------------------------------------------------*/
  92. static int __inline__ amdf_pitch(int min_pitch, int max_pitch, int16_t amp[], int len)
  93. {
  94. int i;
  95. int j;
  96. int acc;
  97. int min_acc;
  98. int pitch;
  99. pitch = min_pitch;
  100. min_acc = INT_MAX;
  101. for (i = max_pitch; i <= min_pitch; i++) {
  102. acc = 0;
  103. for (j = 0; j < len; j++)
  104. acc += abs(amp[i + j] - amp[j]);
  105. if (acc < min_acc) {
  106. min_acc = acc;
  107. pitch = i;
  108. }
  109. }
  110. return pitch;
  111. }
  112. /*- End of function --------------------------------------------------------*/
  113. int plc_rx(plc_state_t *s, int16_t amp[], int len)
  114. {
  115. int i;
  116. int pitch_overlap;
  117. float old_step;
  118. float new_step;
  119. float old_weight;
  120. float new_weight;
  121. float gain;
  122. if (s->missing_samples) {
  123. /* Although we have a real signal, we need to smooth it to fit well
  124. with the synthetic signal we used for the previous block */
  125. /* The start of the real data is overlapped with the next 1/4 cycle
  126. of the synthetic data. */
  127. pitch_overlap = s->pitch >> 2;
  128. if (pitch_overlap > len)
  129. pitch_overlap = len;
  130. gain = 1.0 - s->missing_samples*ATTENUATION_INCREMENT;
  131. if (gain < 0.0)
  132. gain = 0.0;
  133. new_step = 1.0/pitch_overlap;
  134. old_step = new_step*gain;
  135. new_weight = new_step;
  136. old_weight = (1.0 - new_step)*gain;
  137. for (i = 0; i < pitch_overlap; i++) {
  138. amp[i] = fsaturate(old_weight * s->pitchbuf[s->pitch_offset] + new_weight * amp[i]);
  139. if (++s->pitch_offset >= s->pitch)
  140. s->pitch_offset = 0;
  141. new_weight += new_step;
  142. old_weight -= old_step;
  143. if (old_weight < 0.0)
  144. old_weight = 0.0;
  145. }
  146. s->missing_samples = 0;
  147. }
  148. save_history(s, amp, len);
  149. return len;
  150. }
  151. /*- End of function --------------------------------------------------------*/
  152. int plc_fillin(plc_state_t *s, int16_t amp[], int len)
  153. {
  154. int i;
  155. int pitch_overlap;
  156. float old_step;
  157. float new_step;
  158. float old_weight;
  159. float new_weight;
  160. float gain;
  161. int orig_len;
  162. orig_len = len;
  163. if (s->missing_samples == 0) {
  164. /* As the gap in real speech starts we need to assess the last known pitch,
  165. and prepare the synthetic data we will use for fill-in */
  166. normalise_history(s);
  167. s->pitch = amdf_pitch(PLC_PITCH_MIN, PLC_PITCH_MAX, s->history + PLC_HISTORY_LEN - CORRELATION_SPAN - PLC_PITCH_MIN, CORRELATION_SPAN);
  168. /* We overlap a 1/4 wavelength */
  169. pitch_overlap = s->pitch >> 2;
  170. /* Cook up a single cycle of pitch, using a single of the real signal with 1/4
  171. cycle OLA'ed to make the ends join up nicely */
  172. /* The first 3/4 of the cycle is a simple copy */
  173. for (i = 0; i < s->pitch - pitch_overlap; i++)
  174. s->pitchbuf[i] = s->history[PLC_HISTORY_LEN - s->pitch + i];
  175. /* The last 1/4 of the cycle is overlapped with the end of the previous cycle */
  176. new_step = 1.0/pitch_overlap;
  177. new_weight = new_step;
  178. for ( ; i < s->pitch; i++) {
  179. 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;
  180. new_weight += new_step;
  181. }
  182. /* We should now be ready to fill in the gap with repeated, decaying cycles
  183. of what is in pitchbuf */
  184. /* We need to OLA the first 1/4 wavelength of the synthetic data, to smooth
  185. it into the previous real data. To avoid the need to introduce a delay
  186. in the stream, reverse the last 1/4 wavelength, and OLA with that. */
  187. gain = 1.0;
  188. new_step = 1.0 / pitch_overlap;
  189. old_step = new_step;
  190. new_weight = new_step;
  191. old_weight = 1.0 - new_step;
  192. for (i = 0; i < pitch_overlap; i++) {
  193. amp[i] = fsaturate(old_weight * s->history[PLC_HISTORY_LEN - 1 - i] + new_weight * s->pitchbuf[i]);
  194. new_weight += new_step;
  195. old_weight -= old_step;
  196. if (old_weight < 0.0)
  197. old_weight = 0.0;
  198. }
  199. s->pitch_offset = i;
  200. } else {
  201. gain = 1.0 - s->missing_samples*ATTENUATION_INCREMENT;
  202. i = 0;
  203. }
  204. for ( ; gain > 0.0 && i < len; i++) {
  205. amp[i] = s->pitchbuf[s->pitch_offset] * gain;
  206. gain -= ATTENUATION_INCREMENT;
  207. if (++s->pitch_offset >= s->pitch)
  208. s->pitch_offset = 0;
  209. }
  210. for ( ; i < len; i++)
  211. amp[i] = 0;
  212. s->missing_samples += orig_len;
  213. save_history(s, amp, len);
  214. return len;
  215. }
  216. /*- End of function --------------------------------------------------------*/
  217. plc_state_t *plc_init(plc_state_t *s)
  218. {
  219. memset(s, 0, sizeof(*s));
  220. return s;
  221. }
  222. /*- End of function --------------------------------------------------------*/
  223. /*- End of file ------------------------------------------------------------*/
  224. static int reload_module(void)
  225. {
  226. struct ast_variable *var;
  227. struct ast_flags config_flags = { 0 };
  228. struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
  229. if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
  230. return 0;
  231. }
  232. for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
  233. if (!strcasecmp(var->name, "genericplc")) {
  234. ast_set2_flag(&ast_options, ast_true(var->value), AST_OPT_FLAG_GENERIC_PLC);
  235. } else if (!strcasecmp(var->name, "genericplc_on_equal_codecs")) {
  236. ast_set2_flag(&ast_options, ast_true(var->value), AST_OPT_FLAG_GENERIC_PLC_ON_EQUAL_CODECS);
  237. }
  238. }
  239. ast_config_destroy(cfg);
  240. /*
  241. * Force on_equal_codecs to false if generic_plc is false.
  242. */
  243. if (!ast_opt_generic_plc) {
  244. ast_set2_flag(&ast_options, 0, AST_OPT_FLAG_GENERIC_PLC_ON_EQUAL_CODECS);
  245. }
  246. return 0;
  247. }
  248. static int load_module(void)
  249. {
  250. reload_module();
  251. return AST_MODULE_LOAD_SUCCESS;
  252. }
  253. static int unload_module(void)
  254. {
  255. return 0;
  256. }
  257. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PLC",
  258. .support_level = AST_MODULE_SUPPORT_CORE,
  259. .load = load_module,
  260. .unload = unload_module,
  261. .reload = reload_module,
  262. .load_pri = AST_MODPRI_CORE,
  263. .requires = "extconfig",
  264. );