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

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: wsola.c 3553 2011-05-05 06:14:19Z nanang $ */
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, 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 = 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 = 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.. */