1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <pjmedia/wsola.h>
21 #include <pj/log.h>
22 #include <pj/pool.h>
23 #include <pj/os.h>
24 #include <stdio.h>
25 #include <assert.h>
26 
27 #define CLOCK_RATE	    16000
28 #define SAMPLES_PER_FRAME   (10 * CLOCK_RATE / 1000)
29 
30 #define RESET()	    memset(buf1, 0, sizeof(buf1)), \
31 		    memset(buf2, 0, sizeof(buf2)), \
32 		    memset(frm1, 0, sizeof(frm1)), \
33 		    memset(frm2, 0, sizeof(frm2))
34 
35 #if 0
36 void test_find_pitch(void)
37 {
38     enum { ON = 111, FRM_PART_LEN=20 };
39     short buf2[SAMPLES_PER_FRAME*2], buf1[SAMPLES_PER_FRAME*2],
40 	  frm2[SAMPLES_PER_FRAME], frm1[SAMPLES_PER_FRAME];
41     short *ref, *pos;
42 
43     /* Case 1. all contiguous */
44     RESET();
45     ref = buf1 + 10;
46     *ref = ON;
47     frm1[0] = ON;
48 
49     pos = pjmedia_wsola_find_pitch(frm1, SAMPLES_PER_FRAME, NULL, 0,
50 				   buf1, SAMPLES_PER_FRAME*2, NULL, 0, PJ_TRUE);
51     assert(pos == ref);
52 
53     /* Case 2: contiguous buffer, non-contiguous frame */
54     RESET();
55     ref = buf1 + 17;
56     *ref = ON;
57     *(ref+FRM_PART_LEN) = ON;
58     frm1[0] = ON;
59     frm2[0] = ON;
60 
61     /* Noise */
62     buf1[0] = ON;
63 
64     pos = pjmedia_wsola_find_pitch(frm1, FRM_PART_LEN, frm2, SAMPLES_PER_FRAME - FRM_PART_LEN,
65 				   buf1, SAMPLES_PER_FRAME*2, NULL, 0, PJ_TRUE);
66     assert(pos == ref);
67 
68     /* Case 3: non-contiguous buffer, contiguous frame, found in buf1 */
69     RESET();
70     ref = buf1 + 17;
71     *ref = ON;
72     buf2[17] = ON;
73     frm1[0] = ON;
74     frm1[FRM_PART_LEN] = ON;
75 
76     /* Noise */
77     buf1[0] = ON;
78 
79     pos = pjmedia_wsola_find_pitch(frm1, SAMPLES_PER_FRAME, NULL, 0,
80 				   buf1, FRM_PART_LEN,
81 				   buf2, SAMPLES_PER_FRAME,
82 				   PJ_TRUE);
83 
84     assert(pos == ref);
85 }
86 #endif
87 
expand(pj_pool_t * pool,const char * filein,const char * fileout,int expansion_rate100,int lost_rate10,int lost_burst)88 int expand(pj_pool_t *pool, const char *filein, const char *fileout,
89 	   int expansion_rate100, int lost_rate10, int lost_burst)
90 {
91     enum { LOST_RATE = 10 };
92     FILE *in, *out;
93     short frame[SAMPLES_PER_FRAME];
94     pjmedia_wsola *wsola;
95     pj_timestamp elapsed, zero;
96     unsigned samples;
97     int last_lost = 0;
98 
99     /* Lost burst must be > 0 */
100     assert(lost_rate10==0 || lost_burst > 0);
101 
102     in = fopen(filein, "rb");
103     if (!in) return 1;
104     out = fopen(fileout, "wb");
105     if (!out) return 1;
106 
107     pjmedia_wsola_create(pool, CLOCK_RATE, SAMPLES_PER_FRAME, 1, 0, &wsola);
108 
109     samples = 0;
110     elapsed.u64 = 0;
111 
112     while (fread(frame, SAMPLES_PER_FRAME*2, 1, in) == 1) {
113 	pj_timestamp t1, t2;
114 
115 	if (lost_rate10 == 0) {
116 
117 	    /* Expansion */
118 	    pj_get_timestamp(&t1);
119 	    pjmedia_wsola_save(wsola, frame, 0);
120 	    pj_get_timestamp(&t2);
121 
122 	    pj_sub_timestamp(&t2, &t1);
123 	    pj_add_timestamp(&elapsed, &t2);
124 
125 	    fwrite(frame, SAMPLES_PER_FRAME*2, 1, out);
126 
127 	    samples += SAMPLES_PER_FRAME;
128 
129 	    if ((rand() % 100) < expansion_rate100) {
130 
131 		pj_get_timestamp(&t1);
132 		pjmedia_wsola_generate(wsola, frame);
133 		pj_get_timestamp(&t2);
134 
135 		pj_sub_timestamp(&t2, &t1);
136 		pj_add_timestamp(&elapsed, &t2);
137 
138 		samples += SAMPLES_PER_FRAME;
139 
140 		fwrite(frame, SAMPLES_PER_FRAME*2, 1, out);
141 	    }
142 
143 	} else {
144 	    /* Lost */
145 
146 	    if ((rand() % 10) < lost_rate10) {
147 		int burst;
148 
149 		for (burst=0; burst<lost_burst; ++burst) {
150 		    pj_get_timestamp(&t1);
151 		    pjmedia_wsola_generate(wsola, frame);
152 		    pj_get_timestamp(&t2);
153 
154 		    pj_sub_timestamp(&t2, &t1);
155 		    pj_add_timestamp(&elapsed, &t2);
156 
157 		    samples += SAMPLES_PER_FRAME;
158 
159 		    fwrite(frame, SAMPLES_PER_FRAME*2, 1, out);
160 		}
161 		last_lost = 1;
162 	    } else {
163 		pj_get_timestamp(&t1);
164 		pjmedia_wsola_save(wsola, frame, last_lost);
165 		pj_get_timestamp(&t2);
166 
167 		pj_sub_timestamp(&t2, &t1);
168 		pj_add_timestamp(&elapsed, &t2);
169 
170 		samples += SAMPLES_PER_FRAME;
171 
172 		fwrite(frame, SAMPLES_PER_FRAME*2, 1, out);
173 		last_lost = 0;
174 	    }
175 
176 	}
177 
178     }
179 
180     zero.u64 = 0;
181     zero.u64 = pj_elapsed_usec(&zero, &elapsed);
182 
183     zero.u64 = samples * PJ_INT64(1000000) / zero.u64;
184     assert(zero.u32.hi == 0);
185 
186     PJ_LOG(3,("test.c", "Processing: %f Msamples per second",
187 	      zero.u32.lo/1000000.0));
188     PJ_LOG(3,("test.c", "CPU load for current settings: %f%%",
189 	      CLOCK_RATE * 100.0 / zero.u32.lo));
190 
191     pjmedia_wsola_destroy(wsola);
192     fclose(in);
193     fclose(out);
194 
195     return 0;
196 }
197 
save_file(const char * file,short frame[],unsigned count)198 static void save_file(const char *file,
199 		      short frame[], unsigned count)
200 {
201     FILE *f = fopen(file, "wb");
202     fwrite(frame, count, 2, f);
203     fclose(f);
204 }
205 
compress(pj_pool_t * pool,const char * filein,const char * fileout,int rate10)206 int compress(pj_pool_t *pool,
207 	     const char *filein, const char *fileout,
208 	     int rate10)
209 {
210     enum { BUF_CNT = SAMPLES_PER_FRAME * 10 };
211     FILE *in, *out;
212     pjmedia_wsola *wsola;
213     short buf[BUF_CNT];
214     pj_timestamp elapsed, zero;
215     unsigned samples = 0;
216 
217     in = fopen(filein, "rb");
218     if (!in) return 1;
219     out = fopen(fileout, "wb");
220     if (!out) return 1;
221 
222     pjmedia_wsola_create(pool, CLOCK_RATE, SAMPLES_PER_FRAME, 1, 0, &wsola);
223 
224     elapsed.u64 = 0;
225 
226     for (;;) {
227 	unsigned size_del, count;
228 	pj_timestamp t1, t2;
229 	int i;
230 
231 	if (fread(buf, sizeof(buf), 1, in) != 1)
232 	    break;
233 
234 	count = BUF_CNT;
235 	size_del = 0;
236 	pj_get_timestamp(&t1);
237 
238 	for (i=0; i<rate10; ++i) {
239 	    unsigned to_del = SAMPLES_PER_FRAME;
240 #if 0
241 	    /* Method 1: buf1 contiguous */
242 	    pjmedia_wsola_discard(wsola, buf, count, NULL, 0, &to_del);
243 #elif 0
244 	    /* Method 2: split, majority in buf1 */
245 	    assert(count > SAMPLES_PER_FRAME);
246 	    pjmedia_wsola_discard(wsola, buf, count-SAMPLES_PER_FRAME,
247 				  buf+count-SAMPLES_PER_FRAME, SAMPLES_PER_FRAME,
248 				  &to_del);
249 #elif 0
250 	    /* Method 3: split, majority in buf2 */
251 	    assert(count > SAMPLES_PER_FRAME);
252 	    pjmedia_wsola_discard(wsola, buf, SAMPLES_PER_FRAME,
253 				  buf+SAMPLES_PER_FRAME, count-SAMPLES_PER_FRAME,
254 				  &to_del);
255 #elif 1
256 	    /* Method 4: split, each with small length */
257 	    enum { TOT_LEN = 3 * SAMPLES_PER_FRAME };
258 	    unsigned buf1_len = (rand() % TOT_LEN);
259 	    short *ptr = buf + count - TOT_LEN;
260 	    assert(count > TOT_LEN);
261 	    if (buf1_len==0) buf1_len=SAMPLES_PER_FRAME*2;
262 	    pjmedia_wsola_discard(wsola, ptr, buf1_len,
263 				  ptr+buf1_len, TOT_LEN-buf1_len,
264 				  &to_del);
265 #endif
266 	    count -= to_del;
267 	    size_del += to_del;
268 	}
269 	pj_get_timestamp(&t2);
270 
271 	samples += BUF_CNT;
272 
273 	pj_sub_timestamp(&t2, &t1);
274 	pj_add_timestamp(&elapsed, &t2);
275 
276 	assert(size_del >= SAMPLES_PER_FRAME);
277 
278 	fwrite(buf, count, 2, out);
279     }
280 
281     pjmedia_wsola_destroy(wsola);
282     fclose(in);
283     fclose(out);
284 
285     zero.u64 = 0;
286     zero.u64 = pj_elapsed_usec(&zero, &elapsed);
287 
288     zero.u64 = samples * PJ_INT64(1000000) / zero.u64;
289     assert(zero.u32.hi == 0);
290 
291     PJ_LOG(3,("test.c", "Processing: %f Msamples per second",
292 	      zero.u32.lo/1000000.0));
293     PJ_LOG(3,("test.c", "CPU load for current settings: %f%%",
294 	      CLOCK_RATE * 100.0 / zero.u32.lo));
295 
296     return 0;
297 }
298 
299 
mem_test(pj_pool_t * pool)300 static void mem_test(pj_pool_t *pool)
301 {
302     char unused[1024];
303     short   *frame = pj_pool_alloc(pool, 240+4*160);
304     pj_timestamp elapsed, zero, t1, t2;
305     unsigned samples = 0;
306 
307     elapsed.u64 = 0;
308     while (samples < 50000000) {
309 
310 	pj_get_timestamp(&t1);
311 	pjmedia_move_samples(frame, frame+160, 240+2*160);
312 	pj_get_timestamp(&t2);
313 	pj_sub_timestamp(&t2, &t1);
314 
315 	elapsed.u64 += t2.u64;
316 
317 	memset(unused, 0, sizeof(unused));
318 	samples += 160;
319     }
320 
321 
322 
323 
324     zero.u64 = 0;
325     zero.u64 = pj_elapsed_usec(&zero, &elapsed);
326 
327     zero.u64 = samples * PJ_INT64(1000000) / zero.u64;
328     assert(zero.u32.hi == 0);
329 
330     PJ_LOG(3,("test.c", "Processing: %f Msamples per second",
331 	      zero.u32.lo/1000000.0));
332     PJ_LOG(3,("test.c", "CPU load for current settings: %f%%",
333 	      CLOCK_RATE * 100.0 / zero.u32.lo));
334 
335 }
336 
main()337 int main()
338 {
339     pj_caching_pool cp;
340     pj_pool_t *pool;
341     int i, rc;
342 
343     //test_find_pitch();
344 
345     pj_init();
346     pj_caching_pool_init(&cp, NULL, 0);
347     pool = pj_pool_create(&cp.factory, "", 1000, 1000, NULL);
348 
349     srand(2);
350 
351     rc = expand(pool, "galileo16.pcm", "temp1.pcm", 20, 0, 0);
352     rc = compress(pool, "temp1.pcm", "output.pcm", 1);
353 
354     for (i=0; i<2; ++i) {
355 	rc = expand(pool, "output.pcm", "temp1.pcm", 20, 0, 0);
356 	rc = compress(pool, "temp1.pcm", "output.pcm", 1);
357     }
358 
359     if (rc != 0) {
360 	puts("Error");
361 	return 1;
362     }
363 
364 #if 0
365     {
366 	char s[10];
367 	puts("Press ENTER to quit");
368 	fgets(s, sizeof(s), stdin);
369     }
370 #endif
371 
372     return 0;
373 }
374