* Increase history set to 64 to simplify reduction of indexes

* Decrease memory consumption a bit by using bitfields for some bools
* Rework reduction code
* Drop an unnessacary counter
* Before adding a new entry to the history, try to figure out if we already have an existing entry with the same x value and replace that. This fixes a division by zero
* Fix up input x for all functions, according to the time offset


git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2316 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2008-05-01 19:04:42 +00:00
parent 563f4b63cd
commit f49df7a3b0

View file

@ -34,7 +34,7 @@
#include "time-smoother.h" #include "time-smoother.h"
#define HISTORY_MAX 50 #define HISTORY_MAX 64
/* /*
* Implementation of a time smoothing algorithm to synchronize remote * Implementation of a time smoothing algorithm to synchronize remote
@ -61,7 +61,6 @@
struct pa_smoother { struct pa_smoother {
pa_usec_t adjust_time, history_time; pa_usec_t adjust_time, history_time;
pa_bool_t monotonic;
pa_usec_t time_offset; pa_usec_t time_offset;
@ -82,7 +81,9 @@ struct pa_smoother {
double a, b, c; double a, b, c;
pa_bool_t abc_valid; pa_bool_t abc_valid;
pa_bool_t paused; pa_bool_t monotonic:1;
pa_bool_t paused:1;
pa_usec_t pause_time; pa_usec_t pause_time;
}; };
@ -122,39 +123,58 @@ void pa_smoother_free(pa_smoother* s) {
pa_xfree(s); pa_xfree(s);
} }
#define REDUCE(x) \
do { \
x = (x) % HISTORY_MAX; \
} while(FALSE)
#define REDUCE_INC(x) \
do { \
x = ((x)+1) % HISTORY_MAX; \
} while(FALSE)
static void drop_old(pa_smoother *s, pa_usec_t x) { static void drop_old(pa_smoother *s, pa_usec_t x) {
unsigned j;
/* First drop items from history which are too old, but make sure /* Drop items from history which are too old, but make sure to
* to always keep two entries in the history */ * always keep two entries in the history */
for (j = s->n_history; j > 2; j--) { while (s->n_history > 2) {
if (s->history_x[s->history_idx] + s->history_time >= x) { if (s->history_x[s->history_idx] + s->history_time >= x)
/* This item is still valid, and thus all following ones /* This item is still valid, and thus all following ones
* are too, so let's quit this loop */ * are too, so let's quit this loop */
break; break;
}
/* Item is too old, let's drop it */ /* Item is too old, let's drop it */
s->history_idx ++; REDUCE_INC(s->history_idx);
while (s->history_idx >= HISTORY_MAX)
s->history_idx -= HISTORY_MAX;
s->n_history --; s->n_history --;
} }
} }
static void add_to_history(pa_smoother *s, pa_usec_t x, pa_usec_t y) { static void add_to_history(pa_smoother *s, pa_usec_t x, pa_usec_t y) {
unsigned j; unsigned j, i;
pa_assert(s); pa_assert(s);
/* First try to update an existing history entry */
i = s->history_idx;
for (j = s->n_history; j > 0; j--) {
if (s->history_x[i] == x) {
s->history_y[i] = y;
return;
}
REDUCE_INC(i);
}
/* Drop old entries */
drop_old(s, x); drop_old(s, x);
/* Calculate position for new entry */ /* Calculate position for new entry */
j = s->history_idx + s->n_history; j = s->history_idx + s->n_history;
while (j >= HISTORY_MAX) REDUCE(j);
j -= HISTORY_MAX;
/* Fill in entry */ /* Fill in entry */
s->history_x[j] = x; s->history_x[j] = x;
@ -166,6 +186,7 @@ static void add_to_history(pa_smoother *s, pa_usec_t x, pa_usec_t y) {
/* And make sure we don't store more entries than fit in */ /* And make sure we don't store more entries than fit in */
if (s->n_history >= HISTORY_MAX) { if (s->n_history >= HISTORY_MAX) {
s->history_idx += s->n_history - HISTORY_MAX; s->history_idx += s->n_history - HISTORY_MAX;
REDUCE(s->history_idx);
s->n_history = HISTORY_MAX; s->n_history = HISTORY_MAX;
} }
} }
@ -185,9 +206,7 @@ static double avg_gradient(pa_smoother *s, pa_usec_t x) {
ay += s->history_y[i]; ay += s->history_y[i];
c++; c++;
i++; REDUCE_INC(i);
while (i >= HISTORY_MAX)
i -= HISTORY_MAX;
} }
/* Too few measurements, assume gradient of 1 */ /* Too few measurements, assume gradient of 1 */
@ -210,14 +229,12 @@ static double avg_gradient(pa_smoother *s, pa_usec_t x) {
k += dx*dy; k += dx*dy;
t += dx*dx; t += dx*dx;
i++; REDUCE_INC(i);
while (i >= HISTORY_MAX)
i -= HISTORY_MAX;
} }
r = (double) k / t; r = (double) k / t;
return s->monotonic && r < 0 ? 0 : r; return (s->monotonic && r < 0) ? 0 : r;
} }
static void estimate(pa_smoother *s, pa_usec_t x, pa_usec_t *y, double *deriv) { static void estimate(pa_smoother *s, pa_usec_t x, pa_usec_t *y, double *deriv) {
@ -305,14 +322,12 @@ void pa_smoother_put(pa_smoother *s, pa_usec_t x, pa_usec_t y) {
double nde; double nde;
pa_assert(s); pa_assert(s);
pa_assert(x >= s->time_offset);
/* Fix up x value */ /* Fix up x value */
if (s->paused) if (s->paused)
x = s->pause_time; x = s->pause_time;
pa_assert(x >= s->time_offset); x = PA_LIKELY(x >= s->time_offset) ? x - s->time_offset : 0;
x -= s->time_offset;
pa_assert(x >= s->ex); pa_assert(x >= s->ex);
@ -340,15 +355,12 @@ pa_usec_t pa_smoother_get(pa_smoother *s, pa_usec_t x) {
pa_usec_t y; pa_usec_t y;
pa_assert(s); pa_assert(s);
pa_assert(x >= s->time_offset);
/* Fix up x value */ /* Fix up x value */
if (s->paused) if (s->paused)
x = s->pause_time; x = s->pause_time;
pa_assert(x >= s->time_offset); x = PA_LIKELY(x >= s->time_offset) ? x - s->time_offset : 0;
x -= s->time_offset;
pa_assert(x >= s->ex); pa_assert(x >= s->ex);
estimate(s, x, &y, NULL); estimate(s, x, &y, NULL);
@ -397,14 +409,12 @@ pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay)
double nde; double nde;
pa_assert(s); pa_assert(s);
pa_assert(x >= s->time_offset);
/* Fix up x value */ /* Fix up x value */
if (s->paused) if (s->paused)
x = s->pause_time; x = s->pause_time;
pa_assert(x >= s->time_offset); x = PA_LIKELY(x >= s->time_offset) ? x - s->time_offset : 0;
x -= s->time_offset;
pa_assert(x >= s->ex); pa_assert(x >= s->ex);