summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2008-05-30 11:24:37 +0000
committerNanang Izzuddin <nanang@teluu.com>2008-05-30 11:24:37 +0000
commit37c57cd786183e214ae07d461f3391a1d612a013 (patch)
treeb043a48494850a4db0a594681c6b893c38550551 /pjmedia
parentb5931d8f7220aa592d04f626f4d1e71e01bdeeb5 (diff)
Added another WSOLA implementation, PJMEDIA_WSOLA_IMP_WSOLA_LITE, this is used by small devices by default (replacing PJMEDIA_WSOLA_IMP_NULL)
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1971 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/include/pjmedia/config.h6
-rw-r--r--pjmedia/src/pjmedia/wsola.c110
2 files changed, 112 insertions, 4 deletions
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h
index 587055eb..f9015815 100644
--- a/pjmedia/include/pjmedia/config.h
+++ b/pjmedia/include/pjmedia/config.h
@@ -128,6 +128,12 @@
*/
#define PJMEDIA_WSOLA_IMP_WSOLA 1
+/**
+ * This denotes implementation of WSOLA algorithm with faster waveform
+ * similarity calculation. This implementation provides fair quality of
+ * the result with the main advantage of low processing power requirement.
+ */
+#define PJMEDIA_WSOLA_IMP_WSOLA_LITE 2
/**
* Specify type of Waveform based Similarity Overlap and Add (WSOLA) backend
diff --git a/pjmedia/src/pjmedia/wsola.c b/pjmedia/src/pjmedia/wsola.c
index 85c0f25c..1a08f5b5 100644
--- a/pjmedia/src/pjmedia/wsola.c
+++ b/pjmedia/src/pjmedia/wsola.c
@@ -28,8 +28,9 @@
*/
#define THIS_FILE "wsola.c"
+#if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA) || \
+ (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA_LITE)
-#if PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA
/*
* WSOLA implementation using WSOLA
*/
@@ -113,6 +114,72 @@ struct pjmedia_wsola
pj_timestamp ts; /* Running timestamp. */
};
+#if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA_LITE)
+
+/* In this implementation, waveform similarity comparison is done by calculating
+ * the difference of total level between template frame and the target buffer
+ * for each template_cnt samples. The smallest difference value assumed to be
+ * the most similar block. This seems to be naive, however some tests show
+ * acceptable results and the processing speed is amazing.
+ *
+ * diff level = (template[1]+..+template[n]) - (target[1]+..+target[n])
+ */
+static short *find_pitch(short *frm, short *beg, short *end,
+ unsigned template_cnt, int first)
+{
+ short *sr, *best=beg;
+ int best_corr = 0x7FFFFFFF;
+ int frm_sum = 0;
+ unsigned i;
+
+ for (i = 0; i<template_cnt; ++i)
+ frm_sum += frm[i];
+
+ for (sr=beg; sr!=end; ++sr) {
+ int corr = frm_sum;
+ int abs_corr = 0;
+
+ /* Do calculation on 8 samples at once */
+ for (i = 0; i<template_cnt; i+=8) {
+ corr -= (int)sr[i+0] +
+ (int)sr[i+1] +
+ (int)sr[i+2] +
+ (int)sr[i+3] +
+ (int)sr[i+4] +
+ (int)sr[i+5] +
+ (int)sr[i+6] +
+ (int)sr[i+7];
+ }
+
+ /* Reverse back i if template_cnt is not multiplication of 8,
+ * the remaining samples will be processed below.
+ */
+ if (i != template_cnt)
+ i -= 8;
+
+ for (; i<template_cnt; ++i)
+ corr -= (int)sr[i];
+
+ abs_corr = corr > 0? corr : -corr;
+
+ if (first) {
+ if (abs_corr < best_corr) {
+ best_corr = abs_corr;
+ best = sr;
+ }
+ } else {
+ if (abs_corr <= best_corr) {
+ best_corr = abs_corr;
+ best = sr;
+ }
+ }
+ }
+
+ /*TRACE_((THIS_FILE, "found pitch at %u", best-beg));*/
+ return best;
+}
+
+#endif
#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0
/*
@@ -120,6 +187,8 @@ struct pjmedia_wsola
*/
#include <math.h>
+#if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA)
+
static short *find_pitch(short *frm, short *beg, short *end,
unsigned template_cnt, int first)
{
@@ -130,6 +199,7 @@ static short *find_pitch(short *frm, short *beg, short *end,
double corr = 0;
unsigned i;
+ /* Do calculation on 8 samples at once */
for (i=0; i<template_cnt; i += 8) {
corr += ((float)frm[i+0]) * ((float)sr[i+0]) +
((float)frm[i+1]) * ((float)sr[i+1]) +
@@ -140,6 +210,13 @@ static short *find_pitch(short *frm, short *beg, short *end,
((float)frm[i+6]) * ((float)sr[i+6]) +
((float)frm[i+7]) * ((float)sr[i+7]);
}
+
+ /* Reverse back i if template_cnt is not multiplication of 8,
+ * the remaining samples will be processed below.
+ */
+ if (i != template_cnt)
+ i -= 8;
+
for (; i<template_cnt; ++i) {
corr += ((float)frm[i]) * ((float)sr[i]);
}
@@ -161,6 +238,8 @@ static short *find_pitch(short *frm, short *beg, short *end,
return best;
}
+#endif
+
static void overlapp_add(short dst[], unsigned count,
short l[], short r[],
float w[])
@@ -203,6 +282,8 @@ static void create_win(pj_pool_t *pool, float **pw, unsigned count)
#define WINDOW_BITS 15
enum { WINDOW_MAX_VAL = (1 << WINDOW_BITS)-1 };
+#if (PJMEDIA_WSOLA_IMP==PJMEDIA_WSOLA_IMP_WSOLA)
+
static short *find_pitch(short *frm, short *beg, short *end,
unsigned template_cnt, int first)
{
@@ -214,6 +295,7 @@ static short *find_pitch(short *frm, short *beg, short *end,
pj_int64_t corr = 0;
unsigned i;
+ /* Do calculation on 8 samples at once */
for (i=0; i<template_cnt; i+=8) {
corr += ((int)frm[i+0]) * ((int)sr[i+0]) +
((int)frm[i+1]) * ((int)sr[i+1]) +
@@ -224,6 +306,13 @@ static short *find_pitch(short *frm, short *beg, short *end,
((int)frm[i+6]) * ((int)sr[i+6]) +
((int)frm[i+7]) * ((int)sr[i+7]);
}
+
+ /* Reverse back i if template_cnt is not multiplication of 8,
+ * the remaining samples will be processed below.
+ */
+ if (i != template_cnt)
+ i -= 8;
+
for (; i<template_cnt; ++i) {
corr += ((int)frm[i]) * ((int)sr[i]);
}
@@ -245,6 +334,9 @@ static short *find_pitch(short *frm, short *beg, short *end,
return best;
}
+#endif
+
+
static void overlapp_add(short dst[], unsigned count,
short l[], short r[],
pj_uint16_t w[])
@@ -359,6 +451,13 @@ PJ_DEF(pj_status_t) pjmedia_wsola_create( pj_pool_t *pool,
if (wsola->template_size > samples_per_frame)
wsola->template_size = wsola->samples_per_frame;
+ /* Make sure minimal template size is 8, this is required by waveform
+ * similarity calculation (find_pitch()). Moreover, smaller template size
+ * will reduce accuracy.
+ */
+ if (wsola->template_size < 8)
+ wsola->template_size = 8;
+
wsola->buf = (short*)pj_pool_calloc(pool, wsola->buf_cnt,
sizeof(short));
wsola->frm = wsola->buf + wsola->hist_cnt;
@@ -469,17 +568,21 @@ static unsigned compress(pjmedia_wsola *wsola, short *buf, unsigned count,
unsigned frmsz = wsola->samples_per_frame;
unsigned dist;
- if (count <= (del_cnt << 1)) {
+ if ((count - del_cnt) <= frmsz) {
+ //if (count <= (del_cnt << 1)) {
TRACE_((THIS_FILE, "Not enough samples to compress!"));
return samples_del;
}
- start = buf + (frmsz >> 1);
+ //start = buf + (frmsz >> 1);
+ start = buf + del_cnt - samples_del;
end = start + frmsz;
if (end + frmsz > buf + count)
end = buf+count-frmsz;
+ pj_assert(start < end);
+
start = find_pitch(buf, start, end, wsola->template_size, 0);
dist = start - buf;
@@ -817,7 +920,6 @@ PJ_DEF(pj_status_t) pjmedia_wsola_discard( pjmedia_wsola *wsola,
return PJ_SUCCESS;
}
-
#endif /* #if PJMEDIA_WSOLA_IMP.. */