1 /*
2  * SpanDSP - a series of DSP components for telephony
3  *
4  * time_scale.c - Time scaling for linear speech data
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(HAVE_CONFIG_H)
29 #include "config.h"
30 #endif
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <inttypes.h>
35 #include <string.h>
36 #include <fcntl.h>
37 #include <time.h>
38 #include <limits.h>
39 #if defined(HAVE_TGMATH_H)
40 #include <tgmath.h>
41 #endif
42 #if defined(HAVE_MATH_H)
43 #include <math.h>
44 #endif
45 #if defined(HAVE_STDBOOL_H)
46 #include <stdbool.h>
47 #else
48 #include "spandsp/stdbool.h"
49 #endif
50 #include "floating_fudge.h"
51 
52 #include "spandsp/telephony.h"
53 #include "spandsp/alloc.h"
54 #include "spandsp/fast_convert.h"
55 #include "spandsp/vector_int.h"
56 #include "spandsp/saturated.h"
57 #include "spandsp/time_scale.h"
58 
59 #include "spandsp/private/time_scale.h"
60 
61 /*
62     Time scaling for speech, based on the Pointer Interval Controlled
63     OverLap and Add (PICOLA) method, developed by Morita Naotaka.
64  */
65 
amdf_pitch(int min_pitch,int max_pitch,int16_t amp[],int len)66 static __inline__ int amdf_pitch(int min_pitch, int max_pitch, int16_t amp[], int len)
67 {
68     int i;
69     int j;
70     int acc;
71     int min_acc;
72     int pitch;
73 
74     pitch = min_pitch;
75     min_acc = INT_MAX;
76     for (i = max_pitch;  i <= min_pitch;  i++)
77     {
78         acc = 0;
79         for (j = 0;  j < len;  j++)
80             acc += abs(amp[i + j] - amp[j]);
81         /*endfor*/
82         if (acc < min_acc)
83         {
84             min_acc = acc;
85             pitch = i;
86         }
87         /*endif*/
88     }
89     /*endfor*/
90     return pitch;
91 }
92 /*- End of function --------------------------------------------------------*/
93 
overlap_add(int16_t amp1[],int16_t amp2[],int len)94 static __inline__ void overlap_add(int16_t amp1[], int16_t amp2[], int len)
95 {
96     int i;
97     float weight;
98     float step;
99 
100     step = 1.0f/len;
101     weight = 0.0f;
102     for (i = 0;  i < len;  i++)
103     {
104         /* TODO: saturate */
105         amp1[i] = (int16_t) ((float) amp2[i]*(1.0f - weight) + (float) amp1[i]*weight);
106         weight += step;
107     }
108     /*endfor*/
109 }
110 /*- End of function --------------------------------------------------------*/
111 
time_scale_rate(time_scale_state_t * s,float playout_rate)112 SPAN_DECLARE(int) time_scale_rate(time_scale_state_t *s, float playout_rate)
113 {
114     if (playout_rate <= 0.0f)
115         return -1;
116     /*endif*/
117     if (playout_rate >= 0.99f  &&  playout_rate <= 1.01f)
118     {
119         /* Treat rate close to normal speed as exactly normal speed, and
120            avoid divide by zero, and other numerical problems. */
121         playout_rate = 1.0f;
122     }
123     else if (playout_rate < 1.0f)
124     {
125         s->rcomp = playout_rate/(1.0f - playout_rate);
126     }
127     else
128     {
129         s->rcomp = 1.0f/(playout_rate - 1.0f);
130     }
131     /*endif*/
132     s->playout_rate = playout_rate;
133     return 0;
134 }
135 /*- End of function --------------------------------------------------------*/
136 
time_scale(time_scale_state_t * s,int16_t out[],int16_t in[],int len)137 SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], int len)
138 {
139     double lcpf;
140     int pitch;
141     int out_len;
142     int in_len;
143     int k;
144 
145     out_len = 0;
146     in_len = 0;
147 
148     if (s->playout_rate == 1.0f)
149     {
150         vec_copyi16(out, in, len);
151         return len;
152     }
153     /*endif*/
154 
155     /* Top up the buffer */
156     if (s->fill + len < s->buf_len)
157     {
158         /* Cannot continue without more samples */
159         /* Save the residual signal for next time. */
160         vec_copyi16(&s->buf[s->fill], in, len);
161         s->fill += len;
162         return 0;
163     }
164     /*endif*/
165     k = s->buf_len - s->fill;
166     vec_copyi16(&s->buf[s->fill], in, k);
167     in_len += k;
168     s->fill = s->buf_len;
169     while (s->fill == s->buf_len)
170     {
171         while (s->lcp >= s->buf_len)
172         {
173             vec_copyi16(&out[out_len], s->buf, s->buf_len);
174             out_len += s->buf_len;
175             if (len - in_len < s->buf_len)
176             {
177                 /* Cannot continue without more samples */
178                 /* Save the residual signal for next time. */
179                 vec_copyi16(s->buf, &in[in_len], len - in_len);
180                 s->fill = len - in_len;
181                 s->lcp -= s->buf_len;
182                 return out_len;
183             }
184             /*endif*/
185             vec_copyi16(s->buf, &in[in_len], s->buf_len);
186             in_len += s->buf_len;
187             s->lcp -= s->buf_len;
188         }
189         /*endwhile*/
190         if (s->lcp > 0)
191         {
192             vec_copyi16(&out[out_len], s->buf, s->lcp);
193             out_len += s->lcp;
194             vec_movei16(s->buf, &s->buf[s->lcp], s->buf_len - s->lcp);
195             if (len - in_len < s->lcp)
196             {
197                 /* Cannot continue without more samples */
198                 /* Save the residual signal for next time. */
199                 vec_copyi16(&s->buf[s->buf_len - s->lcp], &in[in_len], len - in_len);
200                 s->fill = s->buf_len - s->lcp + len - in_len;
201                 s->lcp = 0;
202                 return out_len;
203             }
204             /*endif*/
205             vec_copyi16(&s->buf[s->buf_len - s->lcp], &in[in_len], s->lcp);
206             in_len += s->lcp;
207             s->lcp = 0;
208         }
209         /*endif*/
210         pitch = amdf_pitch(s->min_pitch, s->max_pitch, s->buf, s->min_pitch);
211         lcpf = (double) pitch*s->rcomp;
212         /* Nudge around to compensate for fractional samples */
213         s->lcp = (int) lcpf;
214         /* Note that s->lcp and lcpf are not the same, as lcpf has a fractional part, and s->lcp doesn't */
215         s->rate_nudge += s->lcp - lcpf;
216         if (s->rate_nudge >= 0.5f)
217         {
218             s->lcp--;
219             s->rate_nudge -= 1.0f;
220         }
221         else if (s->rate_nudge <= -0.5f)
222         {
223             s->lcp++;
224             s->rate_nudge += 1.0f;
225         }
226         /*endif*/
227         if (s->playout_rate < 1.0f)
228         {
229             /* Speed up - drop a pitch period of signal */
230             overlap_add(&s->buf[pitch], s->buf, pitch);
231             vec_copyi16(&s->buf[pitch], &s->buf[2*pitch], s->buf_len - 2*pitch);
232             if (len - in_len < pitch)
233             {
234                 /* Cannot continue without more samples */
235                 /* Save the residual signal for next time. */
236                 vec_copyi16(&s->buf[s->buf_len - pitch], &in[in_len], len - in_len);
237                 s->fill += (len - in_len - pitch);
238                 return out_len;
239             }
240             /*endif*/
241             vec_copyi16(&s->buf[s->buf_len - pitch], &in[in_len], pitch);
242             in_len += pitch;
243         }
244         else
245         {
246             /* Slow down - insert a pitch period of signal */
247             vec_copyi16(&out[out_len], s->buf, pitch);
248             out_len += pitch;
249             overlap_add(s->buf, &s->buf[pitch], pitch);
250         }
251         /*endif*/
252     }
253     /*endwhile*/
254     return out_len;
255 }
256 /*- End of function --------------------------------------------------------*/
257 
time_scale_flush(time_scale_state_t * s,int16_t out[])258 SPAN_DECLARE(int) time_scale_flush(time_scale_state_t *s, int16_t out[])
259 {
260     int len;
261     int pad;
262 
263     if (s->playout_rate < 1.0f)
264         return 0;
265     /*endif*/
266     vec_copyi16(out, s->buf, s->fill);
267     len = s->fill;
268     if (s->playout_rate > 1.0f)
269     {
270         pad = s->fill*(s->playout_rate - 1.0f);
271         vec_zeroi16(&out[len], pad);
272         len += pad;
273     }
274     /*endif*/
275     s->fill = 0;
276     return len;
277 }
278 /*- End of function --------------------------------------------------------*/
279 
time_scale_max_output_len(time_scale_state_t * s,int input_len)280 SPAN_DECLARE(int) time_scale_max_output_len(time_scale_state_t *s, int input_len)
281 {
282     return (int) (input_len*s->playout_rate + s->min_pitch + 1);
283 }
284 /*- End of function --------------------------------------------------------*/
285 
time_scale_init(time_scale_state_t * s,int sample_rate,float playout_rate)286 SPAN_DECLARE(time_scale_state_t *) time_scale_init(time_scale_state_t *s, int sample_rate, float playout_rate)
287 {
288     bool alloced;
289 
290     if (sample_rate > TIME_SCALE_MAX_SAMPLE_RATE)
291         return NULL;
292     /*endif*/
293     alloced = false;
294     if (s == NULL)
295     {
296         if ((s = (time_scale_state_t *) span_alloc(sizeof(*s))) == NULL)
297             return NULL;
298         /*endif*/
299         alloced = true;
300     }
301     /*endif*/
302     s->sample_rate = sample_rate;
303     s->min_pitch = sample_rate/TIME_SCALE_MIN_PITCH;
304     s->max_pitch = sample_rate/TIME_SCALE_MAX_PITCH;
305     s->buf_len = 2*sample_rate/TIME_SCALE_MIN_PITCH;
306     if (time_scale_rate(s, playout_rate))
307     {
308         if (alloced)
309             span_free(s);
310         /*endif*/
311         return NULL;
312     }
313     /*endif*/
314     s->rate_nudge = 0.0f;
315     s->fill = 0;
316     s->lcp = 0;
317     return s;
318 }
319 /*- End of function --------------------------------------------------------*/
320 
time_scale_release(time_scale_state_t * s)321 SPAN_DECLARE(int) time_scale_release(time_scale_state_t *s)
322 {
323     return 0;
324 }
325 /*- End of function --------------------------------------------------------*/
326 
time_scale_free(time_scale_state_t * s)327 SPAN_DECLARE(int) time_scale_free(time_scale_state_t *s)
328 {
329     span_free(s);
330     return 0;
331 }
332 /*- End of function --------------------------------------------------------*/
333 /*- End of file ------------------------------------------------------------*/
334