spandsp: plc.h Source File

spandsp 0.0.6

plc.h
Go to the documentation of this file.
1/*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * plc.h
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2004 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 2.1,
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*! \file */
27
28#if !defined(_SPANDSP_PLC_H_)
29#define _SPANDSP_PLC_H_
30
31/*! \page plc_page Packet loss concealment
32\section plc_page_sec_1 What does it do?
33The packet loss concealment module provides a synthetic fill-in signal, to minimise
34the audible effect of lost packets in VoIP applications. It is not tied to any
35particular codec, and could be used with almost any codec which does not
36specify its own procedure for packet loss concealment.
37
38Where a codec specific concealment procedure exists, that algorithm is usually built
39around knowledge of the characteristics of the particular codec. It will, therefore,
40generally give better results for that particular codec than this generic concealer will.
41
42The PLC code implements an algorithm similar to the one described in Appendix 1 of G.711.
43However, the G.711 algorithm is optimised for 10ms packets. Few people use such small
44packets. 20ms is a much more common value, and longer packets are also quite common. The
45algorithm has been adjusted with this in mind. Also, the G.711 approach causes an
46algorithmic delay, and requires significant buffer manipulation when there is no packet
47loss. The algorithm used here avoids this. It causes no delay, and achieves comparable
48quality with normal speech.
49
50Note that both this algorithm, and the one in G.711 are optimised for speech. For most kinds
51of music a much slower decay on bursts of lost packets give better results.
52
53\section plc_page_sec_2 How does it work?
54While good packets are being received, the plc_rx() routine keeps a record of the trailing
55section of the known speech signal. If a packet is missed, plc_fillin() is called to produce
56a synthetic replacement for the real speech signal. The average mean difference function
57(AMDF) is applied to the last known good signal, to determine its effective pitch.
58Based on this, the last pitch period of signal is saved. Essentially, this cycle of speech
59will be repeated over and over until the real speech resumes. However, several refinements
60are needed to obtain smooth pleasant sounding results.
61
62- The two ends of the stored cycle of speech will not always fit together smoothly. This can
63 cause roughness, or even clicks, at the joins between cycles. To soften this, the
64 1/4 pitch period of real speech preceeding the cycle to be repeated is blended with the last
65 1/4 pitch period of the cycle to be repeated, using an overlap-add (OLA) technique (i.e.
66 in total, the last 5/4 pitch periods of real speech are used).
67
68- The start of the synthetic speech will not always fit together smoothly with the tail of
69 real speech passed on before the erasure was identified. Ideally, we would like to modify
70 the last 1/4 pitch period of the real speech, to blend it into the synthetic speech. However,
71 it is too late for that. We could have delayed the real speech a little, but that would
72 require more buffer manipulation, and hurt the efficiency of the no-lost-packets case
73 (which we hope is the dominant case). Instead we use a degenerate form of OLA to modify
74 the start of the synthetic data. The last 1/4 pitch period of real speech is time reversed,
75 and OLA is used to blend it with the first 1/4 pitch period of synthetic speech. The result
76 seems quite acceptable.
77
78- As we progress into the erasure, the chances of the synthetic signal being anything like
79 correct steadily fall. Therefore, the volume of the synthesized signal is made to decay
80 linearly, such that after 50ms of missing audio it is reduced to silence.
81
82- When real speech resumes, an extra 1/4 pitch period of synthetic speech is blended with the
83 start of the real speech. If the erasure is small, this smoothes the transition. If the erasure
84 is long, and the synthetic signal has faded to zero, the blending softens the start up of the
85 real signal, avoiding a kind of "click" or "pop" effect that might occur with a sudden onset.
86
87\section plc_page_sec_3 How do I use it?
88Before audio is processed, call plc_init() to create an instance of the packet loss
89concealer. For each received audio packet that is acceptable (i.e. not including those being
90dropped for being too late) call plc_rx() to record the content of the packet. Note this may
91modify the packet a little after a period of packet loss, to blend real synthetic data smoothly.
92When a real packet is not available in time, call plc_fillin() to create a sythetic substitute.
93That's it!
94*/
95
96/*! Minimum allowed pitch (66 Hz) */
97#define PLC_PITCH_MIN 120
98/*! Maximum allowed pitch (200 Hz) */
99#define PLC_PITCH_MAX 40
100/*! Maximum pitch OLA window */
101#define PLC_PITCH_OVERLAP_MAX (PLC_PITCH_MIN >> 2)
102/*! The length over which the AMDF function looks for similarity (20 ms) */
103#define CORRELATION_SPAN 160
104/*! History buffer length. The buffer much also be at leat 1.25 times
105 PLC_PITCH_MIN, but that is much smaller than the buffer needs to be for
106 the pitch assessment. */
107#define PLC_HISTORY_LEN (CORRELATION_SPAN + PLC_PITCH_MIN)
108
109/*!
110 The generic packet loss concealer context.
111*/
112 typedef struct
113{
114 /*! Consecutive erased samples */
115 int missing_samples;
116 /*! Current offset into pitch period */
117 int pitch_offset;
118 /*! Pitch estimate */
119 int pitch;
120 /*! Buffer for a cycle of speech */
121 float pitchbuf[PLC_PITCH_MIN];
122 /*! History buffer */
123 int16_t history[PLC_HISTORY_LEN];
124 /*! Current pointer into the history buffer */
125 int buf_ptr;
126} plc_state_t;
127
128
129#if defined(__cplusplus)
130extern "C"
131{
132#endif
133
134/*! Process a block of received audio samples for PLC.
135 \brief Process a block of received audio samples for PLC.
136 \param s The packet loss concealer context.
137 \param amp The audio sample buffer.
138 \param len The number of samples in the buffer.
139 \return The number of samples in the buffer. */
140SPAN_DECLARE(int) plc_rx(plc_state_t *s, int16_t amp[], int len);
141
142/*! Fill-in a block of missing audio samples.
143 \brief Fill-in a block of missing audio samples.
144 \param s The packet loss concealer context.
145 \param amp The audio sample buffer.
146 \param len The number of samples to be synthesised.
147 \return The number of samples synthesized. */
148SPAN_DECLARE(int) plc_fillin(plc_state_t *s, int16_t amp[], int len);
149
150/*! Initialise a packet loss concealer context.
151 \brief Initialise a PLC context.
152 \param s The packet loss concealer context.
153 \return A pointer to the the packet loss concealer context. */
154SPAN_DECLARE(plc_state_t *) plc_init(plc_state_t *s);
155
156/*! Release a packet loss concealer context.
157 \param s The packet loss concealer context.
158 \return 0 for OK. */
159SPAN_DECLARE(int) plc_release(plc_state_t *s);
160
161/*! Free a packet loss concealer context.
162 \param s The packet loss concealer context.
163 \return 0 for OK. */
164SPAN_DECLARE(int) plc_free(plc_state_t *s);
165
166#if defined(__cplusplus)
167}
168#endif
169
170#endif
171/*- End of file ------------------------------------------------------------*/
plc_free
int plc_free(plc_state_t *s)
Definition plc.c:251
plc_fillin
int plc_fillin(plc_state_t *s, int16_t amp[], int len)
Fill-in a block of missing audio samples.
Definition plc.c:159
PLC_HISTORY_LEN
#define PLC_HISTORY_LEN
Definition plc.h:107
PLC_PITCH_MIN
#define PLC_PITCH_MIN
Definition plc.h:97
plc_init
plc_state_t * plc_init(plc_state_t *s)
Initialise a PLC context.
Definition plc.c:233
plc_release
int plc_release(plc_state_t *s)
Definition plc.c:245
plc_rx
int plc_rx(plc_state_t *s, int16_t amp[], int len)
Process a block of received audio samples for PLC.
Definition plc.c:115
plc_state_t
Definition plc.h:113
plc_state_t::pitch_offset
int pitch_offset
Definition plc.h:117
plc_state_t::missing_samples
int missing_samples
Definition plc.h:115
plc_state_t::buf_ptr
int buf_ptr
Definition plc.h:125
plc_state_t::pitch
int pitch
Definition plc.h:119