Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/time_scale.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
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 General Public License version 2, as | |
14 * 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 General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * 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.15 2006/11/19 14:07:25 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #ifdef 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 | |
48 #include "spandsp/telephony.h" | |
49 #include "spandsp/time_scale.h" | |
50 | |
51 /* | |
52 Time scaling for speech, based on the Pointer Interval Controlled | |
53 OverLap and Add (PICOLA) method, developed by Morita Naotaka. | |
54 */ | |
55 | |
56 static __inline__ int amdf_pitch(int min_pitch, int max_pitch, int16_t amp[], int len) | |
57 { | |
58 int i; | |
59 int j; | |
60 int acc; | |
61 int min_acc; | |
62 int pitch; | |
63 | |
64 pitch = min_pitch; | |
65 min_acc = INT_MAX; | |
66 for (i = max_pitch; i <= min_pitch; i++) | |
67 { | |
68 acc = 0; | |
69 for (j = 0; j < len; j++) | |
70 acc += abs(amp[i + j] - amp[j]); | |
71 if (acc < min_acc) | |
72 { | |
73 min_acc = acc; | |
74 pitch = i; | |
75 } | |
76 } | |
77 return pitch; | |
78 } | |
79 /*- End of function --------------------------------------------------------*/ | |
80 | |
81 static __inline__ void overlap_add(int16_t amp1[], int16_t amp2[], int len) | |
82 { | |
83 int i; | |
84 double weight; | |
85 double step; | |
86 | |
87 step = 1.0/len; | |
88 weight = 0.0; | |
89 for (i = 0; i < len; i++) | |
90 { | |
91 /* TODO: saturate */ | |
92 amp2[i] = (int16_t) ((double) amp1[i]*(1.0 - weight) + (double) amp2[i]*weight); | |
93 weight += step; | |
94 } | |
95 } | |
96 /*- End of function --------------------------------------------------------*/ | |
97 | |
98 int time_scale_rate(time_scale_t *s, float rate) | |
99 { | |
100 if (rate <= 0.0) | |
101 return -1; | |
102 /*endif*/ | |
103 if (rate >= 0.99 && rate <= 1.01) | |
104 { | |
105 /* Treat rate close to normal speed as exactly normal speed, and | |
106 avoid divide by zero, and other numerical problems. */ | |
107 rate = 1.0; | |
108 } | |
109 else if (rate < 1.0) | |
110 { | |
111 s->rcomp = rate/(1.0 - rate); | |
112 } | |
113 else | |
114 { | |
115 s->rcomp = 1.0/(rate - 1.0); | |
116 } | |
117 /*endif*/ | |
118 s->rate = rate; | |
119 return 0; | |
120 } | |
121 /*- End of function --------------------------------------------------------*/ | |
122 | |
123 int time_scale_init(time_scale_t *s, float rate) | |
124 { | |
125 if (time_scale_rate(s, rate)) | |
126 return -1; | |
127 /*endif*/ | |
128 s->rate_nudge = 0.0; | |
129 s->fill = 0; | |
130 s->lcp = 0; | |
131 return 0; | |
132 } | |
133 /*- End of function --------------------------------------------------------*/ | |
134 | |
135 int time_scale(time_scale_t *s, int16_t out[], int16_t in[], int len) | |
136 { | |
137 double lcpf; | |
138 int pitch; | |
139 int out_len; | |
140 int in_len; | |
141 int k; | |
142 | |
143 out_len = 0; | |
144 in_len = 0; | |
145 | |
146 /* Top up the buffer */ | |
147 if (s->fill + len < TIME_SCALE_BUF_LEN) | |
148 { | |
149 /* Cannot continue without more samples */ | |
150 memcpy(s->buf + s->fill, in, sizeof(int16_t)*len); | |
151 s->fill += len; | |
152 return out_len; | |
153 } | |
154 k = (TIME_SCALE_BUF_LEN - s->fill); | |
155 memcpy(s->buf + s->fill, in, sizeof(int16_t)*k); | |
156 in_len += k; | |
157 s->fill = TIME_SCALE_BUF_LEN; | |
158 while (s->fill == TIME_SCALE_BUF_LEN) | |
159 { | |
160 while (s->lcp >= TIME_SCALE_BUF_LEN) | |
161 { | |
162 memcpy(out + out_len, s->buf, sizeof(int16_t)*TIME_SCALE_BUF_LEN); | |
163 out_len += TIME_SCALE_BUF_LEN; | |
164 if (len - in_len < TIME_SCALE_BUF_LEN) | |
165 { | |
166 /* Cannot continue without more samples */ | |
167 memcpy(s->buf, in + in_len, sizeof(int16_t)*(len - in_len)); | |
168 s->fill = len - in_len; | |
169 s->lcp -= TIME_SCALE_BUF_LEN; | |
170 return out_len; | |
171 } | |
172 memcpy(s->buf, in + in_len, sizeof(int16_t)*TIME_SCALE_BUF_LEN); | |
173 in_len += TIME_SCALE_BUF_LEN; | |
174 s->lcp -= TIME_SCALE_BUF_LEN; | |
175 } | |
176 if (s->lcp > 0) | |
177 { | |
178 memcpy(out + out_len, s->buf, sizeof(int16_t)*s->lcp); | |
179 out_len += s->lcp; | |
180 memcpy(s->buf, s->buf + s->lcp, sizeof(int16_t)*(TIME_SCALE_BUF_LEN - s->lcp)); | |
181 if (len - in_len < s->lcp) | |
182 { | |
183 /* Cannot continue without more samples */ | |
184 memcpy(s->buf + (TIME_SCALE_BUF_LEN - s->lcp), in + in_len, sizeof(int16_t)*(len - in_len)); | |
185 s->fill = TIME_SCALE_BUF_LEN - s->lcp + len - in_len; | |
186 s->lcp = 0; | |
187 return out_len; | |
188 } | |
189 memcpy(s->buf + (TIME_SCALE_BUF_LEN - s->lcp), in + in_len, sizeof(int16_t)*s->lcp); | |
190 in_len += s->lcp; | |
191 s->lcp = 0; | |
192 } | |
193 if (s->rate == 1.0) | |
194 { | |
195 s->lcp = 0x7FFFFFFF; | |
196 } | |
197 else | |
198 { | |
199 pitch = amdf_pitch(SAMPLE_RATE/TIME_SCALE_MIN_PITCH, SAMPLE_RATE/TIME_SCALE_MAX_PITCH, s->buf, SAMPLE_RATE/TIME_SCALE_MIN_PITCH); | |
200 lcpf = (double) pitch*s->rcomp; | |
201 /* Nudge around to compensate for fractional samples */ | |
202 s->lcp = (int) lcpf; | |
203 /* Note that s->lcp and lcpf are not the same, as lcpf has a fractional part, and s->lcp doesn't */ | |
204 s->rate_nudge += s->lcp - lcpf; | |
205 if (s->rate_nudge >= 0.5) | |
206 { | |
207 s->lcp--; | |
208 s->rate_nudge -= 1.0; | |
209 } | |
210 else if (s->rate_nudge <= -0.5) | |
211 { | |
212 s->lcp++; | |
213 s->rate_nudge += 1.0; | |
214 } | |
215 if (s->rate < 1.0) | |
216 { | |
217 /* Speed up - drop a chunk of data */ | |
218 overlap_add(s->buf, s->buf + pitch, pitch); | |
219 memcpy(&s->buf[pitch], &s->buf[2*pitch], sizeof(int16_t)*(TIME_SCALE_BUF_LEN - 2*pitch)); | |
220 if (len - in_len < pitch) | |
221 { | |
222 /* Cannot continue without more samples */ | |
223 memcpy(s->buf + TIME_SCALE_BUF_LEN - pitch, in + in_len, sizeof(int16_t)*(len - in_len)); | |
224 s->fill += (len - in_len - pitch); | |
225 return out_len; | |
226 } | |
227 memcpy(s->buf + TIME_SCALE_BUF_LEN - pitch, in + in_len, sizeof(int16_t)*pitch); | |
228 in_len += pitch; | |
229 } | |
230 else | |
231 { | |
232 /* Slow down - insert a chunk of data */ | |
233 memcpy(out + out_len, s->buf, sizeof(int16_t)*pitch); | |
234 out_len += pitch; | |
235 overlap_add(s->buf + pitch, s->buf, pitch); | |
236 } | |
237 } | |
238 } | |
239 return out_len; | |
240 } | |
241 /*- End of function --------------------------------------------------------*/ | |
242 /*- End of file ------------------------------------------------------------*/ |