Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/time_scale.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
---|---|
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 * $Id: time_scale.c,v 1.30 2009/02/10 13:06:47 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #if defined(HAVE_CONFIG_H) | |
31 #include "config.h" | |
32 #endif | |
33 | |
34 #include <stdlib.h> | |
35 #include <stdio.h> | |
36 #include <inttypes.h> | |
37 #include <string.h> | |
38 #include <fcntl.h> | |
39 #include <time.h> | |
40 #include <limits.h> | |
41 #if defined(HAVE_TGMATH_H) | |
42 #include <tgmath.h> | |
43 #endif | |
44 #if defined(HAVE_MATH_H) | |
45 #include <math.h> | |
46 #endif | |
47 #include "floating_fudge.h" | |
48 | |
49 #include "spandsp/telephony.h" | |
50 #include "spandsp/fast_convert.h" | |
51 #include "spandsp/time_scale.h" | |
52 #include "spandsp/saturated.h" | |
53 | |
54 #include "spandsp/private/time_scale.h" | |
55 | |
56 /* | |
57 Time scaling for speech, based on the Pointer Interval Controlled | |
58 OverLap and Add (PICOLA) method, developed by Morita Naotaka. | |
59 */ | |
60 | |
61 static __inline__ int amdf_pitch(int min_pitch, int max_pitch, int16_t amp[], int len) | |
62 { | |
63 int i; | |
64 int j; | |
65 int acc; | |
66 int min_acc; | |
67 int pitch; | |
68 | |
69 pitch = min_pitch; | |
70 min_acc = INT_MAX; | |
71 for (i = max_pitch; i <= min_pitch; i++) | |
72 { | |
73 acc = 0; | |
74 for (j = 0; j < len; j++) | |
75 acc += abs(amp[i + j] - amp[j]); | |
76 if (acc < min_acc) | |
77 { | |
78 min_acc = acc; | |
79 pitch = i; | |
80 } | |
81 } | |
82 return pitch; | |
83 } | |
84 /*- End of function --------------------------------------------------------*/ | |
85 | |
86 static __inline__ void overlap_add(int16_t amp1[], int16_t amp2[], int len) | |
87 { | |
88 int i; | |
89 float weight; | |
90 float step; | |
91 | |
92 step = 1.0f/len; | |
93 weight = 0.0f; | |
94 for (i = 0; i < len; i++) | |
95 { | |
96 /* TODO: saturate */ | |
97 amp2[i] = (int16_t) ((float) amp1[i]*(1.0f - weight) + (float) amp2[i]*weight); | |
98 weight += step; | |
99 } | |
100 } | |
101 /*- End of function --------------------------------------------------------*/ | |
102 | |
103 SPAN_DECLARE(int) time_scale_rate(time_scale_state_t *s, float playout_rate) | |
104 { | |
105 if (playout_rate <= 0.0f) | |
106 return -1; | |
107 /*endif*/ | |
108 if (playout_rate >= 0.99f && playout_rate <= 1.01f) | |
109 { | |
110 /* Treat rate close to normal speed as exactly normal speed, and | |
111 avoid divide by zero, and other numerical problems. */ | |
112 playout_rate = 1.0f; | |
113 } | |
114 else if (playout_rate < 1.0f) | |
115 { | |
116 s->rcomp = playout_rate/(1.0f - playout_rate); | |
117 } | |
118 else | |
119 { | |
120 s->rcomp = 1.0f/(playout_rate - 1.0f); | |
121 } | |
122 /*endif*/ | |
123 s->playout_rate = playout_rate; | |
124 return 0; | |
125 } | |
126 /*- End of function --------------------------------------------------------*/ | |
127 | |
128 SPAN_DECLARE(time_scale_state_t *) time_scale_init(time_scale_state_t *s, int sample_rate, float playout_rate) | |
129 { | |
130 int alloced; | |
131 | |
132 if (sample_rate > TIME_SCALE_MAX_SAMPLE_RATE) | |
133 return NULL; | |
134 alloced = FALSE; | |
135 if (s == NULL) | |
136 { | |
137 if ((s = (time_scale_state_t *) malloc(sizeof (*s))) == NULL) | |
138 return NULL; | |
139 /*endif*/ | |
140 alloced = TRUE; | |
141 } | |
142 /*endif*/ | |
143 s->sample_rate = sample_rate; | |
144 s->min_pitch = sample_rate/TIME_SCALE_MIN_PITCH; | |
145 s->max_pitch = sample_rate/TIME_SCALE_MAX_PITCH; | |
146 s->buf_len = 2*sample_rate/TIME_SCALE_MIN_PITCH; | |
147 if (time_scale_rate(s, playout_rate)) | |
148 { | |
149 if (alloced) | |
150 free(s); | |
151 return NULL; | |
152 } | |
153 /*endif*/ | |
154 s->rate_nudge = 0.0f; | |
155 s->fill = 0; | |
156 s->lcp = 0; | |
157 return s; | |
158 } | |
159 /*- End of function --------------------------------------------------------*/ | |
160 | |
161 SPAN_DECLARE(int) time_scale_release(time_scale_state_t *s) | |
162 { | |
163 return 0; | |
164 } | |
165 /*- End of function --------------------------------------------------------*/ | |
166 | |
167 SPAN_DECLARE(int) time_scale_free(time_scale_state_t *s) | |
168 { | |
169 free(s); | |
170 return 0; | |
171 } | |
172 /*- End of function --------------------------------------------------------*/ | |
173 | |
174 SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], int len) | |
175 { | |
176 double lcpf; | |
177 int pitch; | |
178 int out_len; | |
179 int in_len; | |
180 int k; | |
181 | |
182 out_len = 0; | |
183 in_len = 0; | |
184 | |
185 /* Top up the buffer */ | |
186 if (s->fill + len < s->buf_len) | |
187 { | |
188 /* Cannot continue without more samples */ | |
189 memcpy(s->buf + s->fill, in, sizeof(int16_t)*len); | |
190 s->fill += len; | |
191 return out_len; | |
192 } | |
193 k = s->buf_len - s->fill; | |
194 memcpy(s->buf + s->fill, in, sizeof(int16_t)*k); | |
195 in_len += k; | |
196 s->fill = s->buf_len; | |
197 while (s->fill == s->buf_len) | |
198 { | |
199 while (s->lcp >= s->buf_len) | |
200 { | |
201 memcpy(out + out_len, s->buf, sizeof(int16_t)*s->buf_len); | |
202 out_len += s->buf_len; | |
203 if (len - in_len < s->buf_len) | |
204 { | |
205 /* Cannot continue without more samples */ | |
206 memcpy(s->buf, in + in_len, sizeof(int16_t)*(len - in_len)); | |
207 s->fill = len - in_len; | |
208 s->lcp -= s->buf_len; | |
209 return out_len; | |
210 } | |
211 memcpy(s->buf, in + in_len, sizeof(int16_t)*s->buf_len); | |
212 in_len += s->buf_len; | |
213 s->lcp -= s->buf_len; | |
214 } | |
215 if (s->lcp > 0) | |
216 { | |
217 memcpy(out + out_len, s->buf, sizeof(int16_t)*s->lcp); | |
218 out_len += s->lcp; | |
219 memcpy(s->buf, s->buf + s->lcp, sizeof(int16_t)*(s->buf_len - s->lcp)); | |
220 if (len - in_len < s->lcp) | |
221 { | |
222 /* Cannot continue without more samples */ | |
223 memcpy(s->buf + (s->buf_len - s->lcp), in + in_len, sizeof(int16_t)*(len - in_len)); | |
224 s->fill = s->buf_len - s->lcp + len - in_len; | |
225 s->lcp = 0; | |
226 return out_len; | |
227 } | |
228 memcpy(s->buf + (s->buf_len - s->lcp), in + in_len, sizeof(int16_t)*s->lcp); | |
229 in_len += s->lcp; | |
230 s->lcp = 0; | |
231 } | |
232 if (s->playout_rate == 1.0f) | |
233 { | |
234 s->lcp = 0x7FFFFFFF; | |
235 } | |
236 else | |
237 { | |
238 pitch = amdf_pitch(s->min_pitch, s->max_pitch, s->buf, s->min_pitch); | |
239 lcpf = (double) pitch*s->rcomp; | |
240 /* Nudge around to compensate for fractional samples */ | |
241 s->lcp = (int) lcpf; | |
242 /* Note that s->lcp and lcpf are not the same, as lcpf has a fractional part, and s->lcp doesn't */ | |
243 s->rate_nudge += s->lcp - lcpf; | |
244 if (s->rate_nudge >= 0.5f) | |
245 { | |
246 s->lcp--; | |
247 s->rate_nudge -= 1.0f; | |
248 } | |
249 else if (s->rate_nudge <= -0.5f) | |
250 { | |
251 s->lcp++; | |
252 s->rate_nudge += 1.0f; | |
253 } | |
254 if (s->playout_rate < 1.0f) | |
255 { | |
256 /* Speed up - drop a chunk of data */ | |
257 overlap_add(s->buf, s->buf + pitch, pitch); | |
258 memcpy(&s->buf[pitch], &s->buf[2*pitch], sizeof(int16_t)*(s->buf_len - 2*pitch)); | |
259 if (len - in_len < pitch) | |
260 { | |
261 /* Cannot continue without more samples */ | |
262 memcpy(s->buf + s->buf_len - pitch, in + in_len, sizeof(int16_t)*(len - in_len)); | |
263 s->fill += (len - in_len - pitch); | |
264 return out_len; | |
265 } | |
266 memcpy(s->buf + s->buf_len - pitch, in + in_len, sizeof(int16_t)*pitch); | |
267 in_len += pitch; | |
268 } | |
269 else | |
270 { | |
271 /* Slow down - insert a chunk of data */ | |
272 memcpy(out + out_len, s->buf, sizeof(int16_t)*pitch); | |
273 out_len += pitch; | |
274 overlap_add(s->buf + pitch, s->buf, pitch); | |
275 } | |
276 } | |
277 } | |
278 return out_len; | |
279 } | |
280 /*- End of function --------------------------------------------------------*/ | |
281 | |
282 SPAN_DECLARE(int) time_scale_max_output_len(time_scale_state_t *s, int input_len) | |
283 { | |
284 return (int) (input_len*s->playout_rate + s->min_pitch + 1); | |
285 } | |
286 /*- End of function --------------------------------------------------------*/ | |
287 /*- End of file ------------------------------------------------------------*/ |