~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjmedia/src/pjmedia/wsola.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: wsola.c 4537 2013-06-19 06:47:43Z riza $ */
 
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 <pjmedia/circbuf.h>
 
22
#include <pjmedia/errno.h>
 
23
#include <pj/assert.h>
 
24
#include <pj/log.h>
 
25
#include <pj/math.h>
 
26
#include <pj/pool.h>
 
27
 
 
28
/*
 
29
 * This file contains implementation of WSOLA using PJMEDIA_WSOLA_IMP_WSOLA
 
30
 * or PJMEDIA_WSOLA_IMP_NULL
 
31
 */
 
32
#define THIS_FILE   "wsola.c"
 
33
 
 
34
/*
 
35
 * http://trac.pjsip.org/repos/ticket/683:
 
36
 *  Workaround for segfault problem in the fixed point version of create_win()
 
37
 *  on ARM9 platform, possibly due to gcc optimization bug.
 
38
 *
 
39
 *  For now, we will use linear window when floating point is disabled.
 
40
 */
 
41
#ifndef PJMEDIA_WSOLA_LINEAR_WIN
 
42
#   define PJMEDIA_WSOLA_LINEAR_WIN    (!PJ_HAS_FLOATING_POINT)
 
43
#endif
 
44
 
 
45
 
 
46
#if 0
 
47
#   define TRACE_(x)    PJ_LOG(4,x)
 
48
#else
 
49
#   define TRACE_(x)
 
50
#endif
 
51
 
 
52
#if 0
 
53
#   define CHECK_(x)    pj_assert(x)
 
54
#else
 
55
#   define CHECK_(x)
 
56
#endif
 
57
 
 
58
 
 
59
#if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA) || \
 
60
    (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA_LITE)
 
61
 
 
62
/*
 
63
 * WSOLA implementation using WSOLA
 
64
 */
 
65
 
 
66
/* Buffer size including history, in frames */
 
67
#define FRAME_CNT       6
 
68
 
 
69
/* Number of history frames in buffer */
 
70
#define HIST_CNT        1.5
 
71
 
 
72
/* Template size, in msec */
 
73
#define TEMPLATE_PTIME  PJMEDIA_WSOLA_TEMPLATE_LENGTH_MSEC
 
74
 
 
75
/* Hanning window size, in msec */
 
76
#define HANNING_PTIME   PJMEDIA_WSOLA_DELAY_MSEC
 
77
 
 
78
/* Number of frames in erase buffer */
 
79
#define ERASE_CNT       ((unsigned)3)
 
80
 
 
81
/* Minimum distance from template for find_pitch() of expansion, in frames */
 
82
#define EXP_MIN_DIST    0.5
 
83
 
 
84
/* Maximum distance from template for find_pitch() of expansion, in frames */
 
85
#define EXP_MAX_DIST    HIST_CNT
 
86
 
 
87
/* Duration of a continuous synthetic frames after which the volume 
 
88
 * of the synthetic frame will be set to zero with fading-out effect.
 
89
 */
 
90
#define MAX_EXPAND_MSEC PJMEDIA_WSOLA_MAX_EXPAND_MSEC
 
91
 
 
92
 
 
93
/* Buffer content:
 
94
 *
 
95
 *  +---------+-----------+--------------------+
 
96
 *  | history | min_extra | more extra / empty |
 
97
 *  +---------+-----------+--------------------+
 
98
 *  ^         ^           ^                    ^
 
99
 * buf    hist_size   min_extra            buf_size
 
100
 * 
 
101
 * History size (hist_size) is a constant value, initialized upon creation.
 
102
 *
 
103
 * min_extra size is equal to HANNING_PTIME, this samples is useful for 
 
104
 * smoothening samples transition between generated frame & history 
 
105
 * (when PLC is invoked), or between generated samples & normal frame 
 
106
 * (after lost/PLC). Since min_extra samples need to be available at 
 
107
 * any time, this will introduce delay of HANNING_PTIME ms.
 
108
 *
 
109
 * More extra is excess samples produced by PLC (PLC frame generation may 
 
110
 * produce more than exact one frame).
 
111
 *
 
112
 * At any particular time, the buffer will contain at least (hist_size + 
 
113
 * min_extra) samples.
 
114
 *
 
115
 * A "save" operation will append the new frame to the end of the buffer,
 
116
 * return the frame from samples right after history and shift the buffer
 
117
 * by one frame.
 
118
 *
 
119
 */
 
120
 
 
121
/* WSOLA structure */
 
122
struct pjmedia_wsola
 
123
{
 
124
    unsigned             clock_rate;        /* Sampling rate.               */
 
125
    pj_uint16_t          samples_per_frame; /* Samples per frame (const)    */
 
126
    pj_uint16_t          channel_count;     /* Channel countt (const)       */
 
127
    pj_uint16_t          options;           /* Options.                     */
 
128
 
 
129
    pjmedia_circ_buf    *buf;               /* The buffer.                  */
 
130
    pj_int16_t          *erase_buf;         /* Temporary erase buffer.      */
 
131
    pj_int16_t          *merge_buf;         /* Temporary merge buffer.      */
 
132
 
 
133
    pj_uint16_t          buf_size;          /* Total buffer size (const)    */
 
134
    pj_uint16_t          hanning_size;      /* Hanning window size (const)  */
 
135
    pj_uint16_t          templ_size;        /* Template size (const)        */
 
136
    pj_uint16_t          hist_size;         /* History size (const)         */
 
137
 
 
138
    pj_uint16_t          min_extra;         /* Minimum extra (const)        */
 
139
    unsigned             max_expand_cnt;    /* Max # of synthetic samples   */
 
140
    unsigned             fade_out_pos;      /* Last fade-out position       */
 
141
    pj_uint16_t          expand_sr_min_dist;/* Minimum distance from template 
 
142
                                               for find_pitch() on expansion
 
143
                                               (const)                      */
 
144
    pj_uint16_t          expand_sr_max_dist;/* Maximum distance from template 
 
145
                                               for find_pitch() on expansion
 
146
                                               (const)                      */
 
147
 
 
148
#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0
 
149
    float               *hanning;           /* Hanning window.              */
 
150
#else
 
151
    pj_uint16_t         *hanning;           /* Hanning window.              */
 
152
#endif
 
153
 
 
154
    pj_timestamp         ts;                /* Running timestamp.           */
 
155
 
 
156
};
 
157
 
 
158
#if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA_LITE)
 
159
 
 
160
/* In this implementation, waveform similarity comparison is done by calculating
 
161
 * the difference of total level between template frame and the target buffer 
 
162
 * for each template_cnt samples. The smallest difference value assumed to be 
 
163
 * the most similar block. This seems to be naive, however some tests show
 
164
 * acceptable results and the processing speed is amazing.
 
165
 *
 
166
 * diff level = (template[1]+..+template[n]) - (target[1]+..+target[n])
 
167
 */
 
168
static pj_int16_t *find_pitch(pj_int16_t *frm, pj_int16_t *beg, pj_int16_t *end, 
 
169
                         unsigned template_cnt, int first)
 
170
{
 
171
    pj_int16_t *sr, *best=beg;
 
172
    int best_corr = 0x7FFFFFFF;
 
173
    int frm_sum = 0;
 
174
    unsigned i;
 
175
 
 
176
    for (i = 0; i<template_cnt; ++i)
 
177
        frm_sum += frm[i];
 
178
 
 
179
    for (sr=beg; sr!=end; ++sr) {
 
180
        int corr = frm_sum;
 
181
        int abs_corr = 0;
 
182
 
 
183
        /* Do calculation on 8 samples at once */
 
184
        for (i = 0; i<template_cnt-8; i+=8) {
 
185
            corr -= (int)sr[i+0] +
 
186
                    (int)sr[i+1] +
 
187
                    (int)sr[i+2] +
 
188
                    (int)sr[i+3] +
 
189
                    (int)sr[i+4] +
 
190
                    (int)sr[i+5] +
 
191
                    (int)sr[i+6] +
 
192
                    (int)sr[i+7];
 
193
        }
 
194
 
 
195
        /* Process remaining samples */
 
196
        for (; i<template_cnt; ++i)
 
197
            corr -= (int)sr[i];
 
198
 
 
199
        abs_corr = corr > 0? corr : -corr;
 
200
 
 
201
        if (first) {
 
202
            if (abs_corr < best_corr) {
 
203
                best_corr = abs_corr;
 
204
                best = sr;
 
205
            }
 
206
        } else {
 
207
            if (abs_corr <= best_corr) {
 
208
                best_corr = abs_corr;
 
209
                best = sr;
 
210
            }
 
211
        }
 
212
    }
 
213
 
 
214
    /*TRACE_((THIS_FILE, "found pitch at %u", best-beg));*/
 
215
    return best;
 
216
}
 
217
 
 
218
#endif
 
219
 
 
220
#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0
 
221
/*
 
222
 * Floating point version.
 
223
 */
 
224
 
 
225
#if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA)
 
226
 
 
227
static pj_int16_t *find_pitch(pj_int16_t *frm, pj_int16_t *beg, pj_int16_t *end, 
 
228
                         unsigned template_cnt, int first)
 
229
{
 
230
    pj_int16_t *sr, *best=beg;
 
231
    double best_corr = 0;
 
232
 
 
233
    for (sr=beg; sr!=end; ++sr) {
 
234
        double corr = 0;
 
235
        unsigned i;
 
236
 
 
237
        /* Do calculation on 8 samples at once */
 
238
        for (i=0; i<template_cnt-8; i += 8) {
 
239
            corr += ((float)frm[i+0]) * ((float)sr[i+0]) + 
 
240
                    ((float)frm[i+1]) * ((float)sr[i+1]) + 
 
241
                    ((float)frm[i+2]) * ((float)sr[i+2]) + 
 
242
                    ((float)frm[i+3]) * ((float)sr[i+3]) + 
 
243
                    ((float)frm[i+4]) * ((float)sr[i+4]) + 
 
244
                    ((float)frm[i+5]) * ((float)sr[i+5]) + 
 
245
                    ((float)frm[i+6]) * ((float)sr[i+6]) + 
 
246
                    ((float)frm[i+7]) * ((float)sr[i+7]);
 
247
        }
 
248
 
 
249
        /* Process remaining samples. */
 
250
        for (; i<template_cnt; ++i) {
 
251
            corr += ((float)frm[i]) * ((float)sr[i]);
 
252
        }
 
253
 
 
254
        if (first) {
 
255
            if (corr > best_corr) {
 
256
                best_corr = corr;
 
257
                best = sr;
 
258
            }
 
259
        } else {
 
260
            if (corr >= best_corr) {
 
261
                best_corr = corr;
 
262
                best = sr;
 
263
            }
 
264
        }
 
265
    }
 
266
 
 
267
    /*TRACE_((THIS_FILE, "found pitch at %u", best-beg));*/
 
268
    return best;
 
269
}
 
270
 
 
271
#endif
 
272
 
 
273
static void overlapp_add(pj_int16_t dst[], unsigned count,
 
274
                         pj_int16_t l[], pj_int16_t r[],
 
275
                         float w[])
 
276
{
 
277
    unsigned i;
 
278
 
 
279
    for (i=0; i<count; ++i) {
 
280
        dst[i] = (pj_int16_t)(l[i] * w[count-1-i] + r[i] * w[i]);
 
281
    }
 
282
}
 
283
 
 
284
static void overlapp_add_simple(pj_int16_t dst[], unsigned count,
 
285
                                pj_int16_t l[], pj_int16_t r[])
 
286
{
 
287
    float step = (float)(1.0 / count), stepdown = 1.0;
 
288
    unsigned i;
 
289
 
 
290
    for (i=0; i<count; ++i) {
 
291
        dst[i] = (pj_int16_t)(l[i] * stepdown + r[i] * (1-stepdown));
 
292
        stepdown -= step;
 
293
    }
 
294
}
 
295
 
 
296
static void create_win(pj_pool_t *pool, float **pw, unsigned count)
 
297
{
 
298
    unsigned i;
 
299
    float *w = (float*)pj_pool_calloc(pool, count, sizeof(float));
 
300
 
 
301
    *pw = w;
 
302
 
 
303
    for (i=0;i<count; i++) {
 
304
        w[i] = (float)(0.5 - 0.5 * cos(2.0 * PJ_PI * i / (count*2-1)) );
 
305
    }
 
306
}
 
307
 
 
308
#else   /* PJ_HAS_FLOATING_POINT */
 
309
/*
 
310
 * Fixed point version.
 
311
 */
 
312
#define WINDOW_BITS     15
 
313
enum { WINDOW_MAX_VAL = (1 << WINDOW_BITS)-1 };
 
314
 
 
315
#if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA)
 
316
 
 
317
static pj_int16_t *find_pitch(pj_int16_t *frm, pj_int16_t *beg, pj_int16_t *end, 
 
318
                         unsigned template_cnt, int first)
 
319
{
 
320
    pj_int16_t *sr, *best=beg;
 
321
    pj_int64_t best_corr = 0;
 
322
 
 
323
    
 
324
    for (sr=beg; sr!=end; ++sr) {
 
325
        pj_int64_t corr = 0;
 
326
        unsigned i;
 
327
 
 
328
        /* Do calculation on 8 samples at once */
 
329
        for (i=0; i<template_cnt-8; i+=8) {
 
330
            corr += ((int)frm[i+0]) * ((int)sr[i+0]) + 
 
331
                    ((int)frm[i+1]) * ((int)sr[i+1]) + 
 
332
                    ((int)frm[i+2]) * ((int)sr[i+2]) +
 
333
                    ((int)frm[i+3]) * ((int)sr[i+3]) +
 
334
                    ((int)frm[i+4]) * ((int)sr[i+4]) +
 
335
                    ((int)frm[i+5]) * ((int)sr[i+5]) +
 
336
                    ((int)frm[i+6]) * ((int)sr[i+6]) +
 
337
                    ((int)frm[i+7]) * ((int)sr[i+7]);
 
338
        }
 
339
 
 
340
        /* Process remaining samples. */
 
341
        for (; i<template_cnt; ++i) {
 
342
            corr += ((int)frm[i]) * ((int)sr[i]);
 
343
        }
 
344
 
 
345
        if (first) {
 
346
            if (corr > best_corr) {
 
347
                best_corr = corr;
 
348
                best = sr;
 
349
            }
 
350
        } else {
 
351
            if (corr >= best_corr) {
 
352
                best_corr = corr;
 
353
                best = sr;
 
354
            }
 
355
        }
 
356
    }
 
357
 
 
358
    /*TRACE_((THIS_FILE, "found pitch at %u", best-beg));*/
 
359
    return best;
 
360
}
 
361
 
 
362
#endif
 
363
 
 
364
 
 
365
static void overlapp_add(pj_int16_t dst[], unsigned count,
 
366
                         pj_int16_t l[], pj_int16_t r[],
 
367
                         pj_uint16_t w[])
 
368
{
 
369
    unsigned i;
 
370
 
 
371
    for (i=0; i<count; ++i) {
 
372
        dst[i] = (pj_int16_t)(((int)(l[i]) * (int)(w[count-1-i]) + 
 
373
                          (int)(r[i]) * (int)(w[i])) >> WINDOW_BITS);
 
374
    }
 
375
}
 
376
 
 
377
static void overlapp_add_simple(pj_int16_t dst[], unsigned count,
 
378
                                pj_int16_t l[], pj_int16_t r[])
 
379
{
 
380
    int step = ((WINDOW_MAX_VAL+1) / count), 
 
381
        stepdown = WINDOW_MAX_VAL;
 
382
    unsigned i;
 
383
 
 
384
    for (i=0; i<count; ++i) {
 
385
        dst[i]=(pj_int16_t)((l[i] * stepdown + r[i] * (1-stepdown)) >> WINDOW_BITS);
 
386
        stepdown -= step;
 
387
    }
 
388
}
 
389
 
 
390
#if PJ_HAS_INT64 && !PJMEDIA_WSOLA_LINEAR_WIN
 
391
/* approx_cos():
 
392
 *   see: http://www.audiomulch.com/~rossb/code/sinusoids/ 
 
393
 */
 
394
static pj_uint32_t approx_cos( pj_uint32_t x )
 
395
{
 
396
    pj_uint32_t i,j,k;
 
397
 
 
398
    if( x == 0 )
 
399
        return 0xFFFFFFFF;
 
400
 
 
401
    i = x << 1;
 
402
    k = ((x + 0xBFFFFFFD) & 0x80000000) >> 30;
 
403
    j = i - i * ((i & 0x80000000)>>30);
 
404
    j = j >> 15;
 
405
    j = (j * j + j) >> 1;
 
406
    j = j - j * k;
 
407
 
 
408
    return j;
 
409
}
 
410
#endif  /* PJ_HAS_INT64 && .. */
 
411
 
 
412
static void create_win(pj_pool_t *pool, pj_uint16_t **pw, unsigned count)
 
413
{
 
414
    
 
415
    unsigned i;
 
416
    pj_uint16_t *w = (pj_uint16_t*)pj_pool_calloc(pool, count, 
 
417
                                                  sizeof(pj_uint16_t));
 
418
 
 
419
    *pw = w;
 
420
 
 
421
    for (i=0; i<count; i++) {
 
422
#if PJ_HAS_INT64 && !PJMEDIA_WSOLA_LINEAR_WIN
 
423
        pj_uint32_t phase;
 
424
        pj_uint64_t cos_val;
 
425
 
 
426
        /* w[i] = (float)(0.5 - 0.5 * cos(2.0 * PJ_PI * i / (count*2-1)) ); */
 
427
 
 
428
        phase = (pj_uint32_t)(PJ_INT64(0xFFFFFFFF) * i / (count*2-1));
 
429
        cos_val = approx_cos(phase);
 
430
 
 
431
        w[i] = (pj_uint16_t)(WINDOW_MAX_VAL - 
 
432
                              (WINDOW_MAX_VAL * cos_val) / 0xFFFFFFFF);
 
433
#else
 
434
        /* Revert to linear */
 
435
        w[i] = (pj_uint16_t)(i * WINDOW_MAX_VAL / count);
 
436
#endif
 
437
    }
 
438
}
 
439
 
 
440
#endif  /* PJ_HAS_FLOATING_POINT */
 
441
 
 
442
/* Apply fade-in to the buffer.
 
443
 *  - fade_cnt is the number of samples on which the volume
 
444
 *       will go from zero to 100%
 
445
 *  - fade_pos is current sample position within fade_cnt range.
 
446
 *       It is zero for the first sample, so the first sample will
 
447
 *       have zero volume. This value is increasing.
 
448
 */
 
449
static void fade_in(pj_int16_t buf[], int count,
 
450
                    int fade_in_pos, int fade_cnt)
 
451
{
 
452
#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0
 
453
    float fade_pos = (float)fade_in_pos;
 
454
#else
 
455
    int fade_pos = fade_in_pos;
 
456
#endif
 
457
 
 
458
    if (fade_cnt - fade_pos < count) {
 
459
        for (; fade_pos < fade_cnt; ++fade_pos, ++buf) {
 
460
            *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt);
 
461
        }
 
462
        /* Leave the remaining samples as is */
 
463
    } else {
 
464
        pj_int16_t *end = buf + count;
 
465
        for (; buf != end; ++fade_pos, ++buf) {
 
466
            *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt);
 
467
        }
 
468
    }
 
469
}
 
470
 
 
471
/* Apply fade-out to the buffer. */
 
472
static void wsola_fade_out(pjmedia_wsola *wsola, 
 
473
                           pj_int16_t buf[], int count)
 
474
{
 
475
    pj_int16_t *end = buf + count;
 
476
    int fade_cnt = wsola->max_expand_cnt;
 
477
#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0
 
478
    float fade_pos = (float)wsola->fade_out_pos;
 
479
#else
 
480
    int fade_pos = wsola->fade_out_pos;
 
481
#endif
 
482
 
 
483
    if (wsola->fade_out_pos == 0) {
 
484
        pjmedia_zero_samples(buf, count);
 
485
    } else if (fade_pos < count) {
 
486
        for (; fade_pos; --fade_pos, ++buf) {
 
487
            *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt);
 
488
        }
 
489
        if (buf != end)
 
490
            pjmedia_zero_samples(buf, (unsigned)(end - buf));
 
491
        wsola->fade_out_pos = 0;
 
492
    } else {
 
493
        for (; buf != end; --fade_pos, ++buf) {
 
494
            *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt);
 
495
        }
 
496
        wsola->fade_out_pos -= count;
 
497
    }
 
498
}
 
499
 
 
500
 
 
501
PJ_DEF(pj_status_t) pjmedia_wsola_create( pj_pool_t *pool, 
 
502
                                          unsigned clock_rate,
 
503
                                          unsigned samples_per_frame,
 
504
                                          unsigned channel_count,
 
505
                                          unsigned options,
 
506
                                          pjmedia_wsola **p_wsola)
 
507
{
 
508
    pjmedia_wsola *wsola;
 
509
    pj_status_t status;
 
510
 
 
511
    PJ_ASSERT_RETURN(pool && clock_rate && samples_per_frame && p_wsola,
 
512
                     PJ_EINVAL);
 
513
    PJ_ASSERT_RETURN(clock_rate <= 65535, PJ_EINVAL);
 
514
    PJ_ASSERT_RETURN(samples_per_frame < clock_rate, PJ_EINVAL);
 
515
    PJ_ASSERT_RETURN(channel_count > 0, PJ_EINVAL);
 
516
 
 
517
    /* Allocate wsola and initialize vars */
 
518
    wsola = PJ_POOL_ZALLOC_T(pool, pjmedia_wsola);
 
519
    wsola->clock_rate= (pj_uint16_t) clock_rate;
 
520
    wsola->samples_per_frame = (pj_uint16_t) samples_per_frame;
 
521
    wsola->channel_count = (pj_uint16_t) channel_count;
 
522
    wsola->options = (pj_uint16_t) options;
 
523
    wsola->max_expand_cnt = clock_rate * MAX_EXPAND_MSEC / 1000;
 
524
    wsola->fade_out_pos = wsola->max_expand_cnt;
 
525
 
 
526
    /* Create circular buffer */
 
527
    wsola->buf_size = (pj_uint16_t) (samples_per_frame * FRAME_CNT);
 
528
    status = pjmedia_circ_buf_create(pool, wsola->buf_size, &wsola->buf);
 
529
    if (status != PJ_SUCCESS) {
 
530
        PJ_LOG(3, (THIS_FILE, "Failed to create circular buf"));
 
531
        return status;
 
532
    }
 
533
 
 
534
    /* Calculate history size */
 
535
    wsola->hist_size = (pj_uint16_t)(HIST_CNT * samples_per_frame);
 
536
 
 
537
    /* Calculate template size */
 
538
    wsola->templ_size = (pj_uint16_t)(TEMPLATE_PTIME * clock_rate * 
 
539
                                      channel_count / 1000);
 
540
    if (wsola->templ_size > samples_per_frame)
 
541
        wsola->templ_size = wsola->samples_per_frame;
 
542
 
 
543
    /* Calculate hanning window size */
 
544
    wsola->hanning_size = (pj_uint16_t)(HANNING_PTIME * clock_rate * 
 
545
                                        channel_count / 1000);
 
546
    if (wsola->hanning_size > wsola->samples_per_frame)
 
547
        wsola->hanning_size = wsola->samples_per_frame;
 
548
 
 
549
    pj_assert(wsola->templ_size <= wsola->hanning_size);
 
550
 
 
551
    /* Create merge buffer */
 
552
    wsola->merge_buf = (pj_int16_t*) pj_pool_calloc(pool, 
 
553
                                                    wsola->hanning_size,
 
554
                                                    sizeof(pj_int16_t));
 
555
 
 
556
    /* Setup with PLC */
 
557
    if ((options & PJMEDIA_WSOLA_NO_PLC) == 0) {
 
558
        wsola->min_extra = wsola->hanning_size;
 
559
        wsola->expand_sr_min_dist = (pj_uint16_t)
 
560
                                    (EXP_MIN_DIST * wsola->samples_per_frame);
 
561
        wsola->expand_sr_max_dist = (pj_uint16_t)
 
562
                                    (EXP_MAX_DIST * wsola->samples_per_frame);
 
563
    }
 
564
 
 
565
    /* Setup with hanning */
 
566
    if ((options & PJMEDIA_WSOLA_NO_HANNING) == 0) {
 
567
        create_win(pool, &wsola->hanning, wsola->hanning_size);
 
568
    }
 
569
 
 
570
    /* Setup with discard */
 
571
    if ((options & PJMEDIA_WSOLA_NO_DISCARD) == 0) {
 
572
        wsola->erase_buf = (pj_int16_t*)pj_pool_calloc(pool, samples_per_frame *
 
573
                                                       ERASE_CNT,
 
574
                                                       sizeof(pj_int16_t));
 
575
    }
 
576
 
 
577
    /* Generate dummy extra */
 
578
    pjmedia_circ_buf_set_len(wsola->buf, wsola->hist_size + wsola->min_extra);
 
579
 
 
580
    *p_wsola = wsola;
 
581
    return PJ_SUCCESS;
 
582
 
 
583
}
 
584
 
 
585
PJ_DEF(pj_status_t) pjmedia_wsola_destroy(pjmedia_wsola *wsola)
 
586
{
 
587
    /* Nothing to do */
 
588
    PJ_UNUSED_ARG(wsola);
 
589
 
 
590
    return PJ_SUCCESS;
 
591
}
 
592
 
 
593
PJ_DEF(pj_status_t) pjmedia_wsola_set_max_expand(pjmedia_wsola *wsola,
 
594
                                                  unsigned msec)
 
595
{
 
596
    PJ_ASSERT_RETURN(wsola, PJ_EINVAL);
 
597
    wsola->max_expand_cnt = msec * wsola->clock_rate / 1000;
 
598
    return PJ_SUCCESS;
 
599
}
 
600
 
 
601
PJ_DEF(pj_status_t) pjmedia_wsola_reset( pjmedia_wsola *wsola,
 
602
                                         unsigned options)
 
603
{
 
604
    PJ_ASSERT_RETURN(wsola && options==0, PJ_EINVAL);
 
605
    PJ_UNUSED_ARG(options);
 
606
 
 
607
    pjmedia_circ_buf_reset(wsola->buf);
 
608
    pjmedia_circ_buf_set_len(wsola->buf, wsola->hist_size + wsola->min_extra);
 
609
    pjmedia_zero_samples(wsola->buf->start, wsola->buf->len); 
 
610
    wsola->fade_out_pos = wsola->max_expand_cnt;
 
611
 
 
612
    return PJ_SUCCESS;
 
613
}
 
614
 
 
615
 
 
616
static void expand(pjmedia_wsola *wsola, unsigned needed)
 
617
{
 
618
    unsigned generated = 0;
 
619
    unsigned rep;
 
620
 
 
621
    pj_int16_t *reg1, *reg2;
 
622
    unsigned reg1_len, reg2_len;
 
623
 
 
624
    pjmedia_circ_buf_pack_buffer(wsola->buf);
 
625
    pjmedia_circ_buf_get_read_regions(wsola->buf, &reg1, &reg1_len, 
 
626
                                      &reg2, &reg2_len);
 
627
    CHECK_(reg2_len == 0);
 
628
 
 
629
    for (rep=1;; ++rep) {
 
630
        pj_int16_t *start, *templ;
 
631
        unsigned dist;
 
632
 
 
633
        templ = reg1 + reg1_len - wsola->hanning_size;
 
634
        CHECK_(templ - reg1 >= wsola->hist_size);
 
635
 
 
636
        start = find_pitch(templ, 
 
637
                           templ - wsola->expand_sr_max_dist, 
 
638
                           templ - wsola->expand_sr_min_dist,
 
639
                           wsola->templ_size, 
 
640
                           1);
 
641
 
 
642
        /* Should we make sure that "start" is really aligned to
 
643
         * channel #0, in case of stereo? Probably not necessary, as
 
644
         * find_pitch() should have found the best match anyway.
 
645
         */
 
646
 
 
647
        if (wsola->options & PJMEDIA_WSOLA_NO_HANNING) {
 
648
            overlapp_add_simple(wsola->merge_buf, wsola->hanning_size, 
 
649
                                templ, start);
 
650
        } else {
 
651
            /* Check if pointers are in the valid range */
 
652
            CHECK_(templ >= wsola->buf->buf &&
 
653
                   templ + wsola->hanning_size <= 
 
654
                   wsola->buf->buf + wsola->buf->capacity);
 
655
            CHECK_(start >= wsola->buf->buf &&
 
656
                   start + wsola->hanning_size <= 
 
657
                   wsola->buf->buf + wsola->buf->capacity);
 
658
 
 
659
            overlapp_add(wsola->merge_buf, wsola->hanning_size, templ, 
 
660
                         start, wsola->hanning);
 
661
        }
 
662
 
 
663
        /* How many new samples do we have */
 
664
        dist = (unsigned)(templ - start);
 
665
 
 
666
        /* Not enough buffer to hold the result */
 
667
        if (reg1_len + dist > wsola->buf_size) {
 
668
            pj_assert(!"WSOLA buffer size may be to small!");
 
669
            break;
 
670
        }
 
671
 
 
672
        /* Copy the "tail" (excess frame) to the end */
 
673
        pjmedia_move_samples(templ + wsola->hanning_size, 
 
674
                             start + wsola->hanning_size,
 
675
                             dist);
 
676
 
 
677
        /* Copy the merged frame */
 
678
        pjmedia_copy_samples(templ, wsola->merge_buf, wsola->hanning_size);
 
679
 
 
680
        /* We have new samples */
 
681
        reg1_len += dist;
 
682
        pjmedia_circ_buf_set_len(wsola->buf, reg1_len);
 
683
 
 
684
        generated += dist;
 
685
 
 
686
        if (generated >= needed) {
 
687
            TRACE_((THIS_FILE, "WSOLA frame expanded after %d iterations", 
 
688
                    rep));
 
689
            break;
 
690
        }
 
691
    }
 
692
}
 
693
 
 
694
 
 
695
static unsigned compress(pjmedia_wsola *wsola, pj_int16_t *buf, unsigned count,
 
696
                         unsigned del_cnt)
 
697
{
 
698
    unsigned samples_del = 0, rep;
 
699
 
 
700
    for (rep=1; ; ++rep) {
 
701
        pj_int16_t *start, *end;
 
702
        unsigned dist;
 
703
 
 
704
        if (count <= wsola->hanning_size + del_cnt) {
 
705
            TRACE_((THIS_FILE, "Not enough samples to compress!"));
 
706
            return samples_del;
 
707
        }
 
708
 
 
709
        // Make start distance to del_cnt, so discard will be performed in
 
710
        // only one iteration.
 
711
        //start = buf + (frmsz >> 1);
 
712
        start = buf + del_cnt - samples_del;
 
713
        end = start + wsola->samples_per_frame;
 
714
 
 
715
        if (end + wsola->hanning_size > buf + count) {
 
716
            end = buf+count-wsola->hanning_size;
 
717
        }
 
718
 
 
719
        CHECK_(start < end);
 
720
 
 
721
        start = find_pitch(buf, start, end, wsola->templ_size, 0);
 
722
        dist = (unsigned)(start - buf);
 
723
 
 
724
        if (wsola->options & PJMEDIA_WSOLA_NO_HANNING) {
 
725
            overlapp_add_simple(buf, wsola->hanning_size, buf, start);
 
726
        } else {
 
727
            overlapp_add(buf, wsola->hanning_size, buf, start, wsola->hanning);
 
728
        }
 
729
 
 
730
        pjmedia_move_samples(buf + wsola->hanning_size, 
 
731
                             buf + wsola->hanning_size + dist,
 
732
                             count - wsola->hanning_size - dist);
 
733
 
 
734
        count -= dist;
 
735
        samples_del += dist;
 
736
 
 
737
        if (samples_del >= del_cnt) {
 
738
            TRACE_((THIS_FILE, 
 
739
                    "Erased %d of %d requested after %d iteration(s)",
 
740
                    samples_del, del_cnt, rep));
 
741
            break;
 
742
        }
 
743
    }
 
744
 
 
745
    return samples_del;
 
746
}
 
747
 
 
748
 
 
749
 
 
750
PJ_DEF(pj_status_t) pjmedia_wsola_save( pjmedia_wsola *wsola, 
 
751
                                        pj_int16_t frm[], 
 
752
                                        pj_bool_t prev_lost)
 
753
{
 
754
    unsigned buf_len;
 
755
    pj_status_t status;
 
756
 
 
757
    buf_len = pjmedia_circ_buf_get_len(wsola->buf);
 
758
 
 
759
    /* Update vars */
 
760
    wsola->ts.u64 += wsola->samples_per_frame;
 
761
 
 
762
    /* If previous frame was lost, smoothen this frame with the generated one */
 
763
    if (prev_lost) {
 
764
        pj_int16_t *reg1, *reg2;
 
765
        unsigned reg1_len, reg2_len;
 
766
        pj_int16_t *ola_left;
 
767
 
 
768
        /* Trim excessive len */
 
769
        if ((int)buf_len > wsola->hist_size + (wsola->min_extra<<1)) {
 
770
            buf_len = wsola->hist_size + (wsola->min_extra<<1);
 
771
            pjmedia_circ_buf_set_len(wsola->buf, buf_len);
 
772
        }
 
773
 
 
774
        pjmedia_circ_buf_get_read_regions(wsola->buf, &reg1, &reg1_len, 
 
775
                                          &reg2, &reg2_len);
 
776
 
 
777
        CHECK_(pjmedia_circ_buf_get_len(wsola->buf) >= 
 
778
               (unsigned)(wsola->hist_size + (wsola->min_extra<<1)));
 
779
 
 
780
        /* Continue applying fade out to the extra samples */
 
781
        if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) {
 
782
            if (reg2_len == 0) {
 
783
                wsola_fade_out(wsola, reg1 + reg1_len - (wsola->min_extra<<1),
 
784
                               (wsola->min_extra<<1));
 
785
            } else if ((int)reg2_len >= (wsola->min_extra<<1)) {
 
786
                wsola_fade_out(wsola, reg2 + reg2_len - (wsola->min_extra<<1),
 
787
                               (wsola->min_extra<<1));
 
788
            } else {
 
789
                unsigned tmp = (wsola->min_extra<<1) - reg2_len;
 
790
                wsola_fade_out(wsola, reg1 + reg1_len - tmp, tmp);
 
791
                wsola_fade_out(wsola, reg2, reg2_len);
 
792
            }
 
793
        }
 
794
 
 
795
        /* Get the region in buffer to be merged with the frame */
 
796
        if (reg2_len == 0) {
 
797
            ola_left = reg1 + reg1_len - wsola->min_extra;
 
798
        } else if (reg2_len >= wsola->min_extra) {
 
799
            ola_left = reg2 + reg2_len - wsola->min_extra;
 
800
        } else {
 
801
            unsigned tmp;
 
802
 
 
803
            tmp = wsola->min_extra - reg2_len;
 
804
            pjmedia_copy_samples(wsola->merge_buf, reg1 + reg1_len - tmp, tmp);
 
805
            pjmedia_copy_samples(wsola->merge_buf + tmp, reg2, reg2_len);
 
806
            ola_left = wsola->merge_buf;
 
807
        }
 
808
 
 
809
        /* Apply fade-in to the frame before merging */
 
810
        if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) {
 
811
            unsigned count = wsola->min_extra;
 
812
            int fade_in_pos;
 
813
 
 
814
            /* Scale fade_in position based on last fade-out */
 
815
            fade_in_pos = wsola->fade_out_pos * count /
 
816
                          wsola->max_expand_cnt;
 
817
 
 
818
            /* Fade-in it */
 
819
            fade_in(frm, wsola->samples_per_frame,
 
820
                    fade_in_pos, count);
 
821
        }
 
822
 
 
823
        /* Merge it */
 
824
        overlapp_add_simple(frm, wsola->min_extra, ola_left, frm);
 
825
 
 
826
        /* Trim len */
 
827
        buf_len -= wsola->min_extra;
 
828
        pjmedia_circ_buf_set_len(wsola->buf, buf_len);
 
829
 
 
830
    } else if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0 &&
 
831
               wsola->fade_out_pos != wsola->max_expand_cnt) 
 
832
    {
 
833
        unsigned count = wsola->min_extra;
 
834
        int fade_in_pos;
 
835
 
 
836
        /* Fade out the remaining synthetic samples */
 
837
        if (buf_len > wsola->hist_size) {
 
838
            pj_int16_t *reg1, *reg2;
 
839
            unsigned reg1_len, reg2_len;
 
840
 
 
841
            /* Number of samples to fade out */
 
842
            count = buf_len - wsola->hist_size;
 
843
 
 
844
            pjmedia_circ_buf_get_read_regions(wsola->buf, &reg1, &reg1_len, 
 
845
                                              &reg2, &reg2_len);
 
846
 
 
847
            CHECK_(pjmedia_circ_buf_get_len(wsola->buf) >= 
 
848
                   (unsigned)(wsola->hist_size + (wsola->min_extra<<1)));
 
849
 
 
850
            /* Continue applying fade out to the extra samples */
 
851
            if (reg2_len == 0) {
 
852
                wsola_fade_out(wsola, reg1 + reg1_len - count, count);
 
853
            } else if (reg2_len >= count) {
 
854
                wsola_fade_out(wsola, reg2 + reg2_len - count, count);
 
855
            } else {
 
856
                unsigned tmp = count - reg2_len;
 
857
                wsola_fade_out(wsola, reg1 + reg1_len - tmp, tmp);
 
858
                wsola_fade_out(wsola, reg2, reg2_len);
 
859
            }
 
860
        }
 
861
 
 
862
        /* Apply fade-in to the frame */
 
863
        count = wsola->min_extra;
 
864
 
 
865
        /* Scale fade_in position based on last fade-out */
 
866
        fade_in_pos = wsola->fade_out_pos * count /
 
867
                      wsola->max_expand_cnt;
 
868
 
 
869
        /* Fade it in */
 
870
        fade_in(frm, wsola->samples_per_frame,
 
871
                fade_in_pos, count);
 
872
 
 
873
    }
 
874
 
 
875
    wsola->fade_out_pos = wsola->max_expand_cnt;
 
876
 
 
877
    status = pjmedia_circ_buf_write(wsola->buf, frm, wsola->samples_per_frame);
 
878
    if (status != PJ_SUCCESS) {
 
879
        TRACE_((THIS_FILE, "Failed writing to circbuf [err=%d]", status));
 
880
        return status;
 
881
    }
 
882
 
 
883
    status = pjmedia_circ_buf_copy(wsola->buf, wsola->hist_size, frm, 
 
884
                                   wsola->samples_per_frame);
 
885
    if (status != PJ_SUCCESS) {
 
886
        TRACE_((THIS_FILE, "Failed copying from circbuf [err=%d]", status));
 
887
        return status;
 
888
    }
 
889
 
 
890
    return pjmedia_circ_buf_adv_read_ptr(wsola->buf, wsola->samples_per_frame);
 
891
}
 
892
 
 
893
 
 
894
PJ_DEF(pj_status_t) pjmedia_wsola_generate( pjmedia_wsola *wsola, 
 
895
                                            pj_int16_t frm[])
 
896
{
 
897
    unsigned samples_len, samples_req;
 
898
    pj_status_t status = PJ_SUCCESS;
 
899
 
 
900
    CHECK_(pjmedia_circ_buf_get_len(wsola->buf) >= wsola->hist_size + 
 
901
           wsola->min_extra);
 
902
 
 
903
    /* Calculate how many samples in the buffer */
 
904
    samples_len = pjmedia_circ_buf_get_len(wsola->buf) - wsola->hist_size;
 
905
 
 
906
    /* Calculate how many samples are required to be available in the buffer */
 
907
    samples_req = wsola->samples_per_frame + (wsola->min_extra << 1);
 
908
    
 
909
    wsola->ts.u64 += wsola->samples_per_frame;
 
910
 
 
911
    if (samples_len < samples_req) {
 
912
        /* Expand buffer */
 
913
        expand(wsola, samples_req - samples_len);
 
914
        TRACE_((THIS_FILE, "Buf size after expanded = %d", 
 
915
                pjmedia_circ_buf_get_len(wsola->buf)));
 
916
    }
 
917
 
 
918
    status = pjmedia_circ_buf_copy(wsola->buf, wsola->hist_size, frm, 
 
919
                                   wsola->samples_per_frame);
 
920
    if (status != PJ_SUCCESS) {
 
921
        TRACE_((THIS_FILE, "Failed copying from circbuf [err=%d]", status));
 
922
        return status;
 
923
    }
 
924
 
 
925
    pjmedia_circ_buf_adv_read_ptr(wsola->buf, wsola->samples_per_frame);
 
926
 
 
927
    /* Apply fade-out to the frame */
 
928
    if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) {
 
929
        wsola_fade_out(wsola, frm, wsola->samples_per_frame);
 
930
    }
 
931
 
 
932
    return PJ_SUCCESS;
 
933
}
 
934
 
 
935
 
 
936
PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola, 
 
937
                                           pj_int16_t buf1[],
 
938
                                           unsigned buf1_cnt, 
 
939
                                           pj_int16_t buf2[],
 
940
                                           unsigned buf2_cnt,
 
941
                                           unsigned *del_cnt)
 
942
{
 
943
    PJ_ASSERT_RETURN(wsola && buf1 && buf1_cnt && del_cnt, PJ_EINVAL);
 
944
    PJ_ASSERT_RETURN(*del_cnt, PJ_EINVAL);
 
945
 
 
946
    if (buf2_cnt == 0) {
 
947
        /* The whole buffer is contiguous space, straight away. */
 
948
        *del_cnt = compress(wsola, buf1, buf1_cnt, *del_cnt);
 
949
    } else {
 
950
        PJ_ASSERT_RETURN(buf2, PJ_EINVAL);
 
951
 
 
952
        if (buf1_cnt < ERASE_CNT * wsola->samples_per_frame &&
 
953
            buf2_cnt < ERASE_CNT * wsola->samples_per_frame &&
 
954
            wsola->erase_buf == NULL)
 
955
        {
 
956
            /* We need erase_buf but WSOLA was created with 
 
957
             * PJMEDIA_WSOLA_NO_DISCARD flag.
 
958
             */
 
959
            pj_assert(!"WSOLA need erase buffer!");
 
960
            return PJ_EINVALIDOP;
 
961
        }
 
962
 
 
963
        if (buf2_cnt >= ERASE_CNT * wsola->samples_per_frame) {
 
964
            /* Enough space to perform compress in the second buffer. */
 
965
            *del_cnt = compress(wsola, buf2, buf2_cnt, *del_cnt);
 
966
        } else if (buf1_cnt >= ERASE_CNT * wsola->samples_per_frame) {
 
967
            /* Enough space to perform compress in the first buffer, but then
 
968
             * we need to re-arrange the buffers so there is no gap between 
 
969
             * buffers.
 
970
             */
 
971
            unsigned max;
 
972
 
 
973
            *del_cnt = compress(wsola, buf1, buf1_cnt, *del_cnt);
 
974
 
 
975
            max = *del_cnt;
 
976
            if (max > buf2_cnt)
 
977
                max = buf2_cnt;
 
978
 
 
979
            pjmedia_move_samples(buf1 + buf1_cnt - (*del_cnt), buf2, max);
 
980
 
 
981
            if (max < buf2_cnt) {
 
982
                pjmedia_move_samples(buf2, buf2+(*del_cnt), 
 
983
                                     buf2_cnt-max);
 
984
            }
 
985
        } else {
 
986
            /* Not enough samples in either buffers to perform compress. 
 
987
             * Need to combine the buffers in a contiguous space, the erase_buf.
 
988
             */
 
989
            unsigned buf_size = buf1_cnt + buf2_cnt;
 
990
            pj_int16_t *rem;    /* remainder */
 
991
            unsigned rem_cnt;
 
992
 
 
993
            if (buf_size > ERASE_CNT * wsola->samples_per_frame) {
 
994
                buf_size = ERASE_CNT * wsola->samples_per_frame;
 
995
                
 
996
                rem_cnt = buf1_cnt + buf2_cnt - buf_size;
 
997
                rem = buf2 + buf2_cnt - rem_cnt;
 
998
                
 
999
            } else {
 
1000
                rem = NULL;
 
1001
                rem_cnt = 0;
 
1002
            }
 
1003
 
 
1004
            pjmedia_copy_samples(wsola->erase_buf, buf1, buf1_cnt);
 
1005
            pjmedia_copy_samples(wsola->erase_buf+buf1_cnt, buf2, 
 
1006
                                 buf_size-buf1_cnt);
 
1007
 
 
1008
            *del_cnt = compress(wsola, wsola->erase_buf, buf_size, *del_cnt);
 
1009
 
 
1010
            buf_size -= (*del_cnt);
 
1011
 
 
1012
            /* Copy back to buffers */
 
1013
            if (buf_size == buf1_cnt) {
 
1014
                pjmedia_copy_samples(buf1, wsola->erase_buf, buf_size);
 
1015
                if (rem_cnt) {
 
1016
                    pjmedia_move_samples(buf2, rem, rem_cnt);
 
1017
                }
 
1018
            } else if (buf_size < buf1_cnt) {
 
1019
                pjmedia_copy_samples(buf1, wsola->erase_buf, buf_size);
 
1020
                if (rem_cnt) {
 
1021
                    unsigned c = rem_cnt;
 
1022
                    if (c > buf1_cnt-buf_size) {
 
1023
                        c = buf1_cnt-buf_size;
 
1024
                    }
 
1025
                    pjmedia_copy_samples(buf1+buf_size, rem, c);
 
1026
                    rem += c;
 
1027
                    rem_cnt -= c;
 
1028
                    if (rem_cnt)
 
1029
                        pjmedia_move_samples(buf2, rem, rem_cnt);
 
1030
                }
 
1031
            } else {
 
1032
                pjmedia_copy_samples(buf1, wsola->erase_buf, buf1_cnt);
 
1033
                pjmedia_copy_samples(buf2, wsola->erase_buf+buf1_cnt, 
 
1034
                                     buf_size-buf1_cnt);
 
1035
                if (rem_cnt) {
 
1036
                    pjmedia_move_samples(buf2+buf_size-buf1_cnt, rem,
 
1037
                                         rem_cnt);
 
1038
                }
 
1039
            }
 
1040
            
 
1041
        }
 
1042
    }
 
1043
 
 
1044
    return (*del_cnt) > 0 ? PJ_SUCCESS : PJ_ETOOSMALL;
 
1045
}
 
1046
 
 
1047
 
 
1048
#elif PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_NULL
 
1049
/*
 
1050
 * WSOLA implementation using NULL
 
1051
 */
 
1052
 
 
1053
struct pjmedia_wsola
 
1054
{
 
1055
    unsigned samples_per_frame;
 
1056
};
 
1057
 
 
1058
 
 
1059
PJ_DEF(pj_status_t) pjmedia_wsola_create( pj_pool_t *pool, 
 
1060
                                          unsigned clock_rate,
 
1061
                                          unsigned samples_per_frame,
 
1062
                                          unsigned channel_count,
 
1063
                                          unsigned options,
 
1064
                                          pjmedia_wsola **p_wsola)
 
1065
{
 
1066
    pjmedia_wsola *wsola;
 
1067
 
 
1068
    wsola = PJ_POOL_ZALLOC_T(pool, struct pjmedia_wsola);
 
1069
    wsola->samples_per_frame = samples_per_frame;
 
1070
 
 
1071
    PJ_UNUSED_ARG(clock_rate);
 
1072
    PJ_UNUSED_ARG(channel_count);
 
1073
    PJ_UNUSED_ARG(options);
 
1074
 
 
1075
    *p_wsola = wsola;
 
1076
 
 
1077
    return PJ_SUCCESS;
 
1078
}
 
1079
 
 
1080
 
 
1081
PJ_DEF(pj_status_t) pjmedia_wsola_destroy(pjmedia_wsola *wsola)
 
1082
{
 
1083
    PJ_UNUSED_ARG(wsola);
 
1084
    return PJ_SUCCESS;
 
1085
}
 
1086
 
 
1087
 
 
1088
PJ_DEF(pj_status_t) pjmedia_wsola_reset( pjmedia_wsola *wsola,
 
1089
                                         unsigned options)
 
1090
{
 
1091
    PJ_UNUSED_ARG(wsola);
 
1092
    PJ_UNUSED_ARG(options);
 
1093
 
 
1094
    return PJ_SUCCESS;
 
1095
}
 
1096
 
 
1097
 
 
1098
PJ_DEF(pj_status_t) pjmedia_wsola_save( pjmedia_wsola *wsola, 
 
1099
                                        pj_int16_t frm[], 
 
1100
                                        pj_bool_t prev_lost)
 
1101
{
 
1102
    PJ_UNUSED_ARG(wsola);
 
1103
    PJ_UNUSED_ARG(frm);
 
1104
    PJ_UNUSED_ARG(prev_lost);
 
1105
 
 
1106
    return PJ_SUCCESS;
 
1107
}
 
1108
 
 
1109
 
 
1110
PJ_DEF(pj_status_t) pjmedia_wsola_generate( pjmedia_wsola *wsola, 
 
1111
                                            pj_int16_t frm[])
 
1112
{
 
1113
    pjmedia_zero_samples(frm, wsola->samples_per_frame);
 
1114
    return PJ_SUCCESS;
 
1115
}
 
1116
 
 
1117
 
 
1118
PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola, 
 
1119
                                           pj_int16_t buf1[],
 
1120
                                           unsigned buf1_cnt, 
 
1121
                                           pj_int16_t buf2[],
 
1122
                                           unsigned buf2_cnt,
 
1123
                                           unsigned *del_cnt)
 
1124
{
 
1125
    CHECK_(buf1_cnt + buf2_cnt >= wsola->samples_per_frame);
 
1126
 
 
1127
    PJ_UNUSED_ARG(buf1);
 
1128
    PJ_UNUSED_ARG(buf1_cnt);
 
1129
    PJ_UNUSED_ARG(buf2);
 
1130
    PJ_UNUSED_ARG(buf2_cnt);
 
1131
 
 
1132
    *del_cnt = wsola->samples_per_frame;
 
1133
 
 
1134
    return PJ_SUCCESS;
 
1135
}
 
1136
 
 
1137
#endif  /* #if PJMEDIA_WSOLA_IMP.. */
 
1138
 
 
1139