summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarren Salt <linux@youmustbejoking.demon.co.uk>2007-08-15 13:42:38 +0100
committerDarren Salt <linux@youmustbejoking.demon.co.uk>2007-08-15 13:42:38 +0100
commit7047d9e5acf97c91a523c99ccc4b008a35a3e094 (patch)
tree80a7a22b47640a7b97f4f027797abf2d704d07e5
parent27aeb069aa930c0c8fa0e0f41885bbedc69d0bcb (diff)
downloadxine-lib-7047d9e5acf97c91a523c99ccc4b008a35a3e094.tar.gz
xine-lib-7047d9e5acf97c91a523c99ccc4b008a35a3e094.tar.bz2
Fix an audio resampling problem which was causing regular clicking.
The cause was that the resampling code was using only the samples in the buffer but not really handling the transition between two buffers (which it would handle completely independently). The new code remembers the last sample from the previous buffer and uses it in the resampling. We therefore end up one sample behind and without the clicks.
-rw-r--r--ChangeLog1
-rw-r--r--src/post/audio/stretch.c10
-rw-r--r--src/xine-engine/audio_out.c30
-rw-r--r--src/xine-engine/resample.c115
-rw-r--r--src/xine-engine/resample.h17
5 files changed, 121 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index c73a1131d..680dba142 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,6 +15,7 @@ xine-lib (1.1.8) (Unreleased)
* Fix a crash with "dvb:/".
* DVB subtitle fixes: deadlock prevention, thread leakage, spec compliance.
* Allow the DVB input plugin to timeout if it is receiving no signal.
+ * Fix an audio resampling problem which was causing regular clicking.
xine-lib (1.1.7)
* Support libdca (new name for libdts) by shuffling around the dts.h file.
diff --git a/src/post/audio/stretch.c b/src/post/audio/stretch.c
index a1e921e03..054468517 100644
--- a/src/post/audio/stretch.c
+++ b/src/post/audio/stretch.c
@@ -225,6 +225,8 @@ struct post_plugin_stretch_s {
int frames_per_frag;
int frames_per_outfrag;
int num_frames; /* current # of frames on audiofrag */
+
+ int16_t last_sample[RESAMPLE_MAX_CHANNELS];
int64_t pts; /* pts for audiofrag */
@@ -353,12 +355,16 @@ static void stretch_process_fragment( post_audio_port_t *port,
if( !this->params.preserve_pitch ) {
if( this->channels == 2 )
- _x_audio_out_resample_stereo(this->audiofrag, num_frames_in,
+ _x_audio_out_resample_stereo(this->last_sample, this->audiofrag, num_frames_in,
this->outfrag, num_frames_out);
else if( this->channels == 1 )
- _x_audio_out_resample_mono(this->audiofrag, num_frames_in,
+ _x_audio_out_resample_mono(this->last_sample, this->audiofrag, num_frames_in,
this->outfrag, num_frames_out);
} else {
+ if (this->channels == 2)
+ memcpy (this->last_sample, &this->audiofrag[(num_frames_in - 1) * 2], 2 * sizeof (this->last_sample[0]));
+ else if (this->channels == 1)
+ memcpy (this->last_sample, &this->audiofrag[num_frames_in - 1], sizeof (this->last_sample[0]));
if( num_frames_in > num_frames_out )
{
/*
diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c
index 6f5351986..93768224b 100644
--- a/src/xine-engine/audio_out.c
+++ b/src/xine-engine/audio_out.c
@@ -251,6 +251,7 @@ typedef struct {
* sure nobody will change speed without going through xine.c:set_speed_internal */
int slow_fast_audio; /* play audio even on slow/fast speeds */
+ int16_t last_sample[RESAMPLE_MAX_CHANNELS];
audio_buffer_t *frame_buf[2]; /* two buffers for "stackable" conversions */
int16_t *zero_space;
@@ -746,19 +747,19 @@ static audio_buffer_t* prepare_samples( aos_t *this, audio_buffer_t *buf) {
switch (this->input.mode) {
case AO_CAP_MODE_MONO:
ensure_buffer_size(this->frame_buf[1], (this->output.bits>>3), num_output_frames);
- _x_audio_out_resample_mono (buf->mem, buf->num_frames,
+ _x_audio_out_resample_mono (this->last_sample, buf->mem, buf->num_frames,
this->frame_buf[1]->mem, num_output_frames);
buf = swap_frame_buffers(this);
break;
case AO_CAP_MODE_STEREO:
ensure_buffer_size(this->frame_buf[1], (this->output.bits>>3)*2, num_output_frames);
- _x_audio_out_resample_stereo (buf->mem, buf->num_frames,
+ _x_audio_out_resample_stereo (this->last_sample, buf->mem, buf->num_frames,
this->frame_buf[1]->mem, num_output_frames);
buf = swap_frame_buffers(this);
break;
case AO_CAP_MODE_4CHANNEL:
ensure_buffer_size(this->frame_buf[1], (this->output.bits>>3)*4, num_output_frames);
- _x_audio_out_resample_4channel (buf->mem, buf->num_frames,
+ _x_audio_out_resample_4channel (this->last_sample, buf->mem, buf->num_frames,
this->frame_buf[1]->mem, num_output_frames);
buf = swap_frame_buffers(this);
break;
@@ -766,7 +767,7 @@ static audio_buffer_t* prepare_samples( aos_t *this, audio_buffer_t *buf) {
case AO_CAP_MODE_5CHANNEL:
case AO_CAP_MODE_5_1CHANNEL:
ensure_buffer_size(this->frame_buf[1], (this->output.bits>>3)*6, num_output_frames);
- _x_audio_out_resample_6channel (buf->mem, buf->num_frames,
+ _x_audio_out_resample_6channel (this->last_sample, buf->mem, buf->num_frames,
this->frame_buf[1]->mem, num_output_frames);
buf = swap_frame_buffers(this);
break;
@@ -775,6 +776,25 @@ static audio_buffer_t* prepare_samples( aos_t *this, audio_buffer_t *buf) {
/* pass-through modes: no resampling */
break;
}
+ } else {
+ /* maintain last_sample in case we need it */
+ switch (this->input.mode) {
+ case AO_CAP_MODE_MONO:
+ memcpy (this->last_sample, &buf->mem[buf->num_frames - 1], sizeof (this->last_sample[0]));
+ break;
+ case AO_CAP_MODE_STEREO:
+ memcpy (this->last_sample, &buf->mem[(buf->num_frames - 1) * 2], 2 * sizeof (this->last_sample[0]));
+ break;
+ case AO_CAP_MODE_4CHANNEL:
+ memcpy (this->last_sample, &buf->mem[(buf->num_frames - 1) * 4], 4 * sizeof (this->last_sample[0]));
+ break;
+ case AO_CAP_MODE_4_1CHANNEL:
+ case AO_CAP_MODE_5CHANNEL:
+ case AO_CAP_MODE_5_1CHANNEL:
+ memcpy (this->last_sample, &buf->mem[(buf->num_frames - 1) * 6], 6 * sizeof (this->last_sample[0]));
+ break;
+ default:;
+ }
}
/* mode conversion */
@@ -2160,6 +2180,8 @@ xine_audio_port_t *_x_ao_new_port (xine_t *xine, ao_driver_t *driver,
fifo_append (this->free_fifo, buf);
}
+
+ memset (this->last_sample, 0, sizeof (this->last_sample));
/* buffers used for audio conversions */
for (i=0; i<2; i++) {
diff --git a/src/xine-engine/resample.c b/src/xine-engine/resample.c
index a7b16917c..1bc9dfaf9 100644
--- a/src/xine-engine/resample.c
+++ b/src/xine-engine/resample.c
@@ -24,26 +24,34 @@
#include "config.h"
#endif
+#include <string.h>
#include <inttypes.h>
#include "attributes.h"
#include "resample.h"
/* contributed by paul flinders */
-void _x_audio_out_resample_mono(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_mono(int16_t *last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples)
{
unsigned int osample;
/* 16+16 fixed point math */
- uint32_t isample = 0;
- uint32_t istep = ((in_samples-2) << 16)/(out_samples-2);
+ uint32_t isample = 0xFFFF0000U;
+ uint32_t istep = (in_samples << 16) / out_samples + 1;
#ifdef VERBOSE
printf ("Audio : resample %d samples to %d\n",
in_samples, out_samples);
#endif
- for (osample = 0; osample < out_samples - 1; osample++) {
+ for (osample = 0; osample < out_samples && isample >= 0xFFFF0000U; osample++) {
+ uint32_t t = isample&0xffff;
+ output_samples[osample] = (last_sample[0] * (0x10000-t) + input_samples[0] * t) >> 16;
+ isample += istep;
+ }
+
+ for (; osample < out_samples; osample++) {
int s1;
int s2;
int16_t os;
@@ -58,23 +66,31 @@ void _x_audio_out_resample_mono(int16_t* input_samples, uint32_t in_samples,
isample += istep;
}
- output_samples[out_samples-1] = input_samples[in_samples-1];
+ last_sample[0] = input_samples[in_samples - 1];
}
-void _x_audio_out_resample_stereo(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_stereo(int16_t *last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples)
{
unsigned int osample;
/* 16+16 fixed point math */
- uint32_t isample = 0;
- uint32_t istep = ((in_samples-2) << 16)/(out_samples-2);
+ uint32_t isample = 0xFFFF0000U;
+ uint32_t istep = (in_samples << 16) / out_samples + 1;
#ifdef VERBOSE
printf ("Audio : resample %d samples to %d\n",
in_samples, out_samples);
#endif
- for (osample = 0; osample < out_samples - 1; osample++) {
+ for (osample = 0; osample < out_samples && isample >= 0xFFFF0000U; osample++) {
+ uint32_t t = isample&0xffff;
+ output_samples[osample*2 ] = (last_sample[0] * (0x10000-t) + input_samples[0] * t) >> 16;
+ output_samples[osample*2+1] = (last_sample[1] * (0x10000-t) + input_samples[1] * t) >> 16;
+ isample += istep;
+ }
+
+ for (; osample < out_samples; osample++) {
int s1;
int s2;
int16_t os;
@@ -94,25 +110,34 @@ void _x_audio_out_resample_stereo(int16_t* input_samples, uint32_t in_samples,
output_samples[(osample * 2 )+1] = os;
isample += istep;
}
- output_samples[out_samples*2-2] = input_samples[in_samples*2-2];
- output_samples[out_samples*2-1] = input_samples[in_samples*2-1];
+ memcpy (last_sample, &input_samples[in_samples*2-2], 2 * sizeof (last_sample[0]));
}
-void _x_audio_out_resample_4channel(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_4channel(int16_t *last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples)
{
unsigned int osample;
/* 16+16 fixed point math */
- uint32_t isample = 0;
- uint32_t istep = ((in_samples-2) << 16)/(out_samples-2);
+ uint32_t isample = 0xFFFF0000U;
+ uint32_t istep = (in_samples << 16) / out_samples + 1;
#ifdef VERBOSE
printf ("Audio : resample %d samples to %d\n",
in_samples, out_samples);
#endif
- for (osample = 0; osample < out_samples - 1; osample++) {
+ for (osample = 0; osample < out_samples && isample >= 0xFFFF0000U; osample++) {
+ uint32_t t = isample&0xffff;
+ output_samples[osample*4 ] = (last_sample[0] * (0x10000-t) + input_samples[0] * t) >> 16;
+ output_samples[osample*4+1] = (last_sample[1] * (0x10000-t) + input_samples[1] * t) >> 16;
+ output_samples[osample*4+2] = (last_sample[2] * (0x10000-t) + input_samples[2] * t) >> 16;
+ output_samples[osample*4+3] = (last_sample[3] * (0x10000-t) + input_samples[3] * t) >> 16;
+ isample += istep;
+ }
+
+ for (; osample < out_samples; osample++) {
int s1;
int s2;
int16_t os;
@@ -145,28 +170,35 @@ void _x_audio_out_resample_4channel(int16_t* input_samples, uint32_t in_samples,
isample += istep;
}
- output_samples[out_samples*4-4] = input_samples[in_samples*4-4];
- output_samples[out_samples*4-3] = input_samples[in_samples*4-3];
- output_samples[out_samples*4-2] = input_samples[in_samples*4-2];
- output_samples[out_samples*4-1] = input_samples[in_samples*4-1];
-
+ memcpy (last_sample, &input_samples[in_samples*4-4], 4 * sizeof (last_sample[0]));
}
-void _x_audio_out_resample_5channel(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_5channel(int16_t *last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples)
{
unsigned int osample;
/* 16+16 fixed point math */
- uint32_t isample = 0;
- uint32_t istep = ((in_samples-2) << 16)/(out_samples-2);
+ uint32_t isample = 0xFFFF0000U;
+ uint32_t istep = (in_samples << 16) / out_samples + 1;
#ifdef VERBOSE
printf ("Audio : resample %d samples to %d\n",
in_samples, out_samples);
#endif
- for (osample = 0; osample < out_samples - 1; osample++) {
+ for (osample = 0; osample < out_samples && isample >= 0xFFFF0000U; osample++) {
+ uint32_t t = isample&0xffff;
+ output_samples[osample*5 ] = (last_sample[0] * (0x10000-t) + input_samples[0] * t) >> 16;
+ output_samples[osample*5+1] = (last_sample[1] * (0x10000-t) + input_samples[1] * t) >> 16;
+ output_samples[osample*5+2] = (last_sample[2] * (0x10000-t) + input_samples[2] * t) >> 16;
+ output_samples[osample*5+3] = (last_sample[3] * (0x10000-t) + input_samples[3] * t) >> 16;
+ output_samples[osample*5+4] = (last_sample[4] * (0x10000-t) + input_samples[4] * t) >> 16;
+ isample += istep;
+ }
+
+ for (; osample < out_samples; osample++) {
int s1;
int s2;
int16_t os;
@@ -205,29 +237,36 @@ void _x_audio_out_resample_5channel(int16_t* input_samples, uint32_t in_samples,
isample += istep;
}
-
- output_samples[out_samples*5-5] = input_samples[in_samples*5-5];
- output_samples[out_samples*5-4] = input_samples[in_samples*5-4];
- output_samples[out_samples*5-3] = input_samples[in_samples*5-3];
- output_samples[out_samples*5-2] = input_samples[in_samples*5-2];
- output_samples[out_samples*5-1] = input_samples[in_samples*5-1];
+ memcpy (last_sample, &input_samples[in_samples*5-5], 5 * sizeof (last_sample[0]));
}
-void _x_audio_out_resample_6channel(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_6channel(int16_t *last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples)
{
unsigned int osample;
/* 16+16 fixed point math */
- uint32_t isample = 0;
- uint32_t istep = ((in_samples-2) << 16)/(out_samples-2);
+ uint32_t isample = 0xFFFF0000U;
+ uint32_t istep = (in_samples << 16) / out_samples + 1;
#ifdef VERBOSE
printf ("Audio : resample %d samples to %d\n",
in_samples, out_samples);
#endif
- for (osample = 0; osample < out_samples - 1; osample++) {
+ for (osample = 0; osample < out_samples && isample >= 0xFFFF0000U; osample++) {
+ uint32_t t = isample&0xffff;
+ output_samples[osample*6 ] = (last_sample[0] * (0x10000-t) + input_samples[0] * t) >> 16;
+ output_samples[osample*6+1] = (last_sample[1] * (0x10000-t) + input_samples[1] * t) >> 16;
+ output_samples[osample*6+2] = (last_sample[2] * (0x10000-t) + input_samples[2] * t) >> 16;
+ output_samples[osample*6+3] = (last_sample[3] * (0x10000-t) + input_samples[3] * t) >> 16;
+ output_samples[osample*6+4] = (last_sample[4] * (0x10000-t) + input_samples[4] * t) >> 16;
+ output_samples[osample*6+5] = (last_sample[5] * (0x10000-t) + input_samples[5] * t) >> 16;
+ isample += istep;
+ }
+
+ for (; osample < out_samples; osample++) {
int s1;
int s2;
int16_t os;
@@ -272,13 +311,7 @@ void _x_audio_out_resample_6channel(int16_t* input_samples, uint32_t in_samples,
isample += istep;
}
-
- output_samples[out_samples*6-6] = input_samples[in_samples*6-6];
- output_samples[out_samples*6-5] = input_samples[in_samples*6-5];
- output_samples[out_samples*6-4] = input_samples[in_samples*6-4];
- output_samples[out_samples*6-3] = input_samples[in_samples*6-3];
- output_samples[out_samples*6-2] = input_samples[in_samples*6-2];
- output_samples[out_samples*6-1] = input_samples[in_samples*6-1];
+ memcpy (last_sample, &input_samples[in_samples*6-6], 6 * sizeof (last_sample[0]));
}
void _x_audio_out_resample_8to16(int8_t* input_samples,
diff --git a/src/xine-engine/resample.h b/src/xine-engine/resample.h
index e5aad1afa..1fd478d06 100644
--- a/src/xine-engine/resample.h
+++ b/src/xine-engine/resample.h
@@ -27,19 +27,26 @@
#ifndef HAVE_RESAMPLE_H
#define HAVE_RESAMPLE_H
-void _x_audio_out_resample_stereo(int16_t* input_samples, uint32_t in_samples,
+#define RESAMPLE_MAX_CHANNELS 6
+
+void _x_audio_out_resample_stereo(int16_t* last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples) XINE_PROTECTED;
-void _x_audio_out_resample_mono(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_mono(int16_t* last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples) XINE_PROTECTED;
-void _x_audio_out_resample_4channel(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_4channel(int16_t* last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples) XINE_PROTECTED;
-void _x_audio_out_resample_5channel(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_5channel(int16_t* last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples) XINE_PROTECTED;
-void _x_audio_out_resample_6channel(int16_t* input_samples, uint32_t in_samples,
+void _x_audio_out_resample_6channel(int16_t* last_sample,
+ int16_t* input_samples, uint32_t in_samples,
int16_t* output_samples, uint32_t out_samples) XINE_PROTECTED;
void _x_audio_out_resample_8to16(int8_t* input_samples,