From 6170a88309be3bba23eee69149a6c2505bc66bbd Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Mon, 9 Aug 2004 06:31:41 +0000 Subject: [PATCH] Signed-off-by: James Courtier-Dutton This patch fixes a number of different bugs in pcm_rate.c. 1) Resampling now works for rate 192000 -> 8000. 2) zero samples are not accidentally inserted into the stream any more. 3) Corrects period size calculations. 4) Prevents avail_min and xfer_align being less than 1. --- src/pcm/pcm_rate.c | 83 +++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index 68025750..a6bc6443 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -27,8 +27,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - -#include +#include #include #include "pcm_local.h" #include "pcm_plugin.h" @@ -45,7 +44,8 @@ const char *_snd_module_pcm_rate = ""; #ifndef DOC_HIDDEN -#define LINEAR_DIV (1<<16) +/* LINEAR_DIV needs to be large enough to handle resampling from 192000 -> 8000 */ +#define LINEAR_DIV (1<<19) enum rate_type { RATE_TYPE_LINEAR, /* linear interpolation */ @@ -58,7 +58,7 @@ typedef struct { struct { int init; int16_t old_sample, new_sample; - int sum; + int64_t sum; } linear; } u; } snd_pcm_rate_state_t; @@ -168,6 +168,9 @@ static void snd_pcm_rate_expand(const snd_pcm_channel_area_t *dst_areas, assert(src_frames1 <= src_frames); } } + if (dst_frames != dst_frames1) { + SNDERR("dst_frames %lu, dst_frames1 %lu, src_frames %lu, src_frames1 %lu\n", dst_frames, dst_frames1, src_frames, src_frames1); + } states->u.linear.old_sample = old_sample; states->u.linear.new_sample = new_sample; states++; @@ -194,17 +197,18 @@ static void snd_pcm_rate_shrink(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t src_frames1 = 0; snd_pcm_uframes_t dst_frames1 = 0; int16_t sample = 0; + unsigned int pos = 0; for (channel = 0; channel < channels; ++channel) { const snd_pcm_channel_area_t *src_area = &src_areas[channel]; const snd_pcm_channel_area_t *dst_area = &dst_areas[channel]; - unsigned int pos; - int sum; + int64_t sum; const char *src; char *dst; int src_step, dst_step; sum = states->u.linear.sum; - pos = 0; + //int16_t old_sample = states->u.linear.old_sample; + pos = LINEAR_DIV/2; /* Start at 0.5 */ states->u.linear.init = 0; src = snd_pcm_channel_area_addr(src_area, src_offset); dst = snd_pcm_channel_area_addr(dst_area, dst_offset); @@ -223,26 +227,25 @@ static void snd_pcm_rate_shrink(const snd_pcm_channel_area_t *dst_areas, src_frames1++; pos += get_increment; if (pos >= LINEAR_DIV) { - int s = sample; pos -= LINEAR_DIV; - sum += s * (get_increment - pos); - sum /= LINEAR_DIV; - sample = sum; goto *put; #define PUT16_END after_put #include "plugin_ops.h" #undef PUT16_END after_put: dst += dst_step; - sum = s * pos; dst_frames1++; assert(dst_frames1 <= dst_frames); - } else - sum += sample * get_increment; + } } + states->u.linear.sum = sum; + states->u.linear.old_sample = sample; states++; } + if (dst_frames != dst_frames1) { + SNDERR("dst %lu, dst1 %lu, src %lu, src1 %lu pos = %u\n", dst_frames, dst_frames1, src_frames, src_frames1, pos ); + } } #endif /* DOC_HIDDEN */ @@ -254,9 +257,9 @@ static snd_pcm_sframes_t snd_pcm_rate_client_frames(snd_pcm_t *pcm, snd_pcm_sfra return 0; /* Round toward zero */ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) - return muldiv_down(frames, LINEAR_DIV, rate->pitch); + return muldiv_near(frames, LINEAR_DIV, rate->pitch); else - return muldiv_down(frames, rate->pitch, LINEAR_DIV); + return muldiv_near(frames, rate->pitch, LINEAR_DIV); } static snd_pcm_sframes_t snd_pcm_rate_slave_frames(snd_pcm_t *pcm, snd_pcm_sframes_t frames) @@ -264,9 +267,9 @@ static snd_pcm_sframes_t snd_pcm_rate_slave_frames(snd_pcm_t *pcm, snd_pcm_sfram snd_pcm_rate_t *rate = pcm->private_data; /* Round toward zero */ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) - return muldiv_down(frames, rate->pitch, LINEAR_DIV); + return muldiv_near(frames, rate->pitch, LINEAR_DIV); else - return muldiv_down(frames, LINEAR_DIV, rate->pitch); + return muldiv_near(frames, LINEAR_DIV, rate->pitch); } static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params) @@ -488,7 +491,7 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) rate->func = snd_pcm_rate_shrink; /* pitch is get_increment */ } - rate->pitch = (((u_int64_t)dst_rate * LINEAR_DIV) + src_rate - 1) / src_rate; + rate->pitch = (((u_int64_t)dst_rate * LINEAR_DIV) + (src_rate / 2)) / src_rate; assert(!rate->states); assert(!rate->pareas); rate->states = malloc(channels * sizeof(*rate->states)); @@ -581,56 +584,60 @@ static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) params->boundary = boundary1; sparams->boundary = boundary2; if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { - rate->pitch = (((u_int64_t)slave->period_size * LINEAR_DIV) + pcm->period_size - 1) / pcm->period_size; + rate->pitch = (((u_int64_t)slave->period_size * LINEAR_DIV) + (pcm->period_size/2) ) / pcm->period_size; do { - snd_pcm_uframes_t cframes; + snd_pcm_uframes_t cframes,cframes_test; - cframes = snd_pcm_rate_client_frames(pcm, slave->period_size - 1); - if (cframes == pcm->period_size - 1) + cframes = snd_pcm_rate_client_frames(pcm, slave->period_size ); + if (cframes == pcm->period_size ) break; - if (cframes > pcm->period_size - 1) { + if (cframes > pcm->period_size ) { rate->pitch++; - if ((snd_pcm_uframes_t)snd_pcm_rate_client_frames(pcm, slave->period_size - 1) < pcm->period_size - 1) { - SNDERR("Unable to satisfy pitch condition (%i/%i - %li/%li)\n", slave->rate, pcm->rate, slave->period_size - 1, pcm->period_size - 1); + cframes_test = snd_pcm_rate_client_frames(pcm, slave->period_size ); + if (cframes_test < pcm->period_size ) { + SNDERR("Unable to satisfy pitch condition (%i/%i - %li/%li)\n", slave->rate, pcm->rate, slave->period_size, pcm->period_size); return -EIO; } } else { rate->pitch--; - if ((snd_pcm_uframes_t)snd_pcm_rate_client_frames(pcm, slave->period_size - 1) > pcm->period_size - 1) { - SNDERR("Unable to satisfy pitch condition (%i/%i - %li/%li)\n", slave->rate, pcm->rate, slave->period_size - 1, pcm->period_size - 1); + cframes_test = snd_pcm_rate_client_frames(pcm, slave->period_size ); + if (cframes_test > pcm->period_size) { + SNDERR("Unable to satisfy pitch condition (%i/%i - %li/%li)\n", slave->rate, pcm->rate, slave->period_size, pcm->period_size); return -EIO; } } } while (1); - assert((snd_pcm_uframes_t)snd_pcm_rate_client_frames(pcm, slave->period_size - 1) == pcm->period_size - 1); + assert((snd_pcm_uframes_t)snd_pcm_rate_client_frames(pcm, slave->period_size ) == pcm->period_size ); } else { - rate->pitch = (((u_int64_t)pcm->period_size * LINEAR_DIV) + slave->period_size - 1) / slave->period_size; + rate->pitch = (((u_int64_t)pcm->period_size * LINEAR_DIV) + (slave->period_size/2) ) / slave->period_size; do { snd_pcm_uframes_t cframes; - cframes = snd_pcm_rate_slave_frames(pcm, pcm->period_size - 1); - if (cframes == slave->period_size - 1) + cframes = snd_pcm_rate_slave_frames(pcm, pcm->period_size ); + if (cframes == slave->period_size ) break; - if (cframes > slave->period_size - 1) { + if (cframes > slave->period_size ) { rate->pitch++; - if ((snd_pcm_uframes_t)snd_pcm_rate_slave_frames(pcm, pcm->period_size - 1) < slave->period_size - 1) { - SNDERR("Unable to satisfy pitch condition (%i/%i - %li/%li)\n", slave->rate, pcm->rate, slave->period_size - 1, pcm->period_size - 1); + if ((snd_pcm_uframes_t)snd_pcm_rate_slave_frames(pcm, pcm->period_size ) < slave->period_size ) { + SNDERR("Unable to satisfy pitch condition (%i/%i - %li/%li)\n", slave->rate, pcm->rate, slave->period_size, pcm->period_size); return -EIO; } } else { rate->pitch--; - if ((snd_pcm_uframes_t)snd_pcm_rate_slave_frames(pcm, pcm->period_size - 1) > slave->period_size - 1) { - SNDERR("Unable to satisfy pitch condition (%i/%i - %li/%li)\n", slave->rate, pcm->rate, slave->period_size - 1, pcm->period_size - 1); + if ((snd_pcm_uframes_t)snd_pcm_rate_slave_frames(pcm, pcm->period_size) > slave->period_size ) { + SNDERR("Unable to satisfy pitch condition (%i/%i - %li/%li)\n", slave->rate, pcm->rate, slave->period_size , pcm->period_size ); return -EIO; } } } while (1); - assert((snd_pcm_uframes_t)snd_pcm_rate_slave_frames(pcm, pcm->period_size - 1) == slave->period_size - 1); + assert((snd_pcm_uframes_t)snd_pcm_rate_slave_frames(pcm, pcm->period_size ) == slave->period_size ); } recalc(pcm, &sparams->avail_min); rate->orig_avail_min = sparams->avail_min; recalc(pcm, &sparams->xfer_align); recalc(pcm, &sparams->start_threshold); + if (sparams->avail_min < 1) sparams->avail_min = 1; + if (sparams->xfer_align < 1) sparams->xfer_align = 1; if (sparams->start_threshold <= slave->buffer_size) { if (sparams->start_threshold > (slave->buffer_size / sparams->avail_min) * sparams->avail_min) sparams->start_threshold = (slave->buffer_size / sparams->avail_min) * sparams->avail_min; -- 2.47.1