mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-10 19:31:12 +00:00
7647f7fc4e
Original commit message from CVS: * gst/audioresample/debug.c: * gst/audioresample/gstaudioresample.c: add room for extra overlap samples when asked to transform size protect against possible mem corruption and check for discrepancies between written size and outbuffer's size so we can warn for potential problems * gst/audioresample/resample.c: (resample_init), (resample_get_output_size_for_input), (resample_get_output_size), (resample_set_n_channels), (resample_set_format): set debug level based on RESAMPLE_DEBUG env var make sure that get_output_size* returns a whole number of sample_size set sample_size each time either channel or format is set * gst/audioresample/resample_chunk.c: (resample_scale_chunk): * gst/audioresample/resample_functable.c: (resample_scale_functable): * gst/audioresample/resample_ref.c: (resample_scale_ref): remove r->sample_size, it's done in resample.c now add some debugging to the ref implementation make sure we only give back bytes that are wholes of the sample size
209 lines
5.7 KiB
C
209 lines
5.7 KiB
C
/* Resampling library
|
|
* Copyright (C) <2001> David A. Schleef <ds@schleef.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <liboil/liboil.h>
|
|
|
|
#include "resample.h"
|
|
#include "buffer.h"
|
|
#include "debug.h"
|
|
|
|
|
|
static double
|
|
resample_sinc_window (double x, double halfwidth, double scale)
|
|
{
|
|
double y;
|
|
|
|
if (x == 0)
|
|
return 1.0;
|
|
if (x < -halfwidth || x > halfwidth)
|
|
return 0.0;
|
|
|
|
y = sin (x * M_PI * scale) / (x * M_PI * scale) * scale;
|
|
|
|
x /= halfwidth;
|
|
y *= (1 - x * x) * (1 - x * x);
|
|
|
|
return y;
|
|
}
|
|
|
|
void
|
|
resample_scale_chunk (ResampleState * r)
|
|
{
|
|
if (r->need_reinit) {
|
|
RESAMPLE_DEBUG ("sample size %d", r->sample_size);
|
|
|
|
if (r->buffer)
|
|
free (r->buffer);
|
|
r->buffer_len = r->sample_size * 1000;
|
|
r->buffer = malloc (r->buffer_len);
|
|
memset (r->buffer, 0, r->buffer_len);
|
|
|
|
r->i_inc = r->o_rate / r->i_rate;
|
|
r->o_inc = r->i_rate / r->o_rate;
|
|
RESAMPLE_DEBUG ("i_inc %g o_inc %g", r->i_inc, r->o_inc);
|
|
|
|
r->i_start = -r->i_inc * r->filter_length;
|
|
|
|
r->need_reinit = 0;
|
|
|
|
#if 0
|
|
if (r->i_inc < 1.0) {
|
|
r->sinc_scale = r->i_inc;
|
|
if (r->sinc_scale == 0.5) {
|
|
/* strange things happen at integer multiples */
|
|
r->sinc_scale = 1.0;
|
|
}
|
|
} else {
|
|
r->sinc_scale = 1.0;
|
|
}
|
|
#else
|
|
r->sinc_scale = 1.0;
|
|
#endif
|
|
}
|
|
|
|
while (r->o_size > 0) {
|
|
double midpoint;
|
|
int i;
|
|
int j;
|
|
|
|
RESAMPLE_DEBUG ("i_start %g", r->i_start);
|
|
midpoint = r->i_start + (r->filter_length - 1) * 0.5 * r->i_inc;
|
|
if (midpoint > 0.5 * r->i_inc) {
|
|
RESAMPLE_ERROR ("inconsistent state");
|
|
}
|
|
while (midpoint < -0.5 * r->i_inc) {
|
|
AudioresampleBuffer *buffer;
|
|
|
|
buffer = audioresample_buffer_queue_pull (r->queue, r->sample_size);
|
|
if (buffer == NULL) {
|
|
RESAMPLE_ERROR ("buffer_queue_pull returned NULL");
|
|
return;
|
|
}
|
|
|
|
r->i_start += r->i_inc;
|
|
RESAMPLE_DEBUG ("pulling (i_start = %g)", r->i_start);
|
|
|
|
midpoint += r->i_inc;
|
|
memmove (r->buffer, r->buffer + r->sample_size,
|
|
r->buffer_len - r->sample_size);
|
|
|
|
memcpy (r->buffer + r->buffer_len - r->sample_size, buffer->data,
|
|
r->sample_size);
|
|
audioresample_buffer_unref (buffer);
|
|
}
|
|
|
|
switch (r->format) {
|
|
case RESAMPLE_FORMAT_S16:
|
|
for (i = 0; i < r->n_channels; i++) {
|
|
double acc = 0;
|
|
double offset;
|
|
double x;
|
|
|
|
for (j = 0; j < r->filter_length; j++) {
|
|
offset = (r->i_start + j * r->i_inc) * r->o_inc;
|
|
x = *(int16_t *) (r->buffer + i * sizeof (int16_t) +
|
|
j * r->sample_size);
|
|
acc +=
|
|
resample_sinc_window (offset, r->filter_length * 0.5,
|
|
r->sinc_scale) * x;
|
|
}
|
|
if (acc < -32768.0)
|
|
acc = -32768.0;
|
|
if (acc > 32767.0)
|
|
acc = 32767.0;
|
|
|
|
*(int16_t *) (r->o_buf + i * sizeof (int16_t)) = rint (acc);
|
|
}
|
|
break;
|
|
case RESAMPLE_FORMAT_S32:
|
|
for (i = 0; i < r->n_channels; i++) {
|
|
double acc = 0;
|
|
double offset;
|
|
double x;
|
|
|
|
for (j = 0; j < r->filter_length; j++) {
|
|
offset = (r->i_start + j * r->i_inc) * r->o_inc;
|
|
x = *(int32_t *) (r->buffer + i * sizeof (int32_t) +
|
|
j * r->sample_size);
|
|
acc +=
|
|
resample_sinc_window (offset, r->filter_length * 0.5,
|
|
r->sinc_scale) * x;
|
|
}
|
|
if (acc < -2147483648.0)
|
|
acc = -2147483648.0;
|
|
if (acc > 2147483647.0)
|
|
acc = 2147483647.0;
|
|
|
|
*(int32_t *) (r->o_buf + i * sizeof (int32_t)) = rint (acc);
|
|
}
|
|
break;
|
|
case RESAMPLE_FORMAT_F32:
|
|
for (i = 0; i < r->n_channels; i++) {
|
|
double acc = 0;
|
|
double offset;
|
|
double x;
|
|
|
|
for (j = 0; j < r->filter_length; j++) {
|
|
offset = (r->i_start + j * r->i_inc) * r->o_inc;
|
|
x = *(float *) (r->buffer + i * sizeof (float) +
|
|
j * r->sample_size);
|
|
acc +=
|
|
resample_sinc_window (offset, r->filter_length * 0.5,
|
|
r->sinc_scale) * x;
|
|
}
|
|
|
|
*(float *) (r->o_buf + i * sizeof (float)) = acc;
|
|
}
|
|
break;
|
|
case RESAMPLE_FORMAT_F64:
|
|
for (i = 0; i < r->n_channels; i++) {
|
|
double acc = 0;
|
|
double offset;
|
|
double x;
|
|
|
|
for (j = 0; j < r->filter_length; j++) {
|
|
offset = (r->i_start + j * r->i_inc) * r->o_inc;
|
|
x = *(double *) (r->buffer + i * sizeof (double) +
|
|
j * r->sample_size);
|
|
acc +=
|
|
resample_sinc_window (offset, r->filter_length * 0.5,
|
|
r->sinc_scale) * x;
|
|
}
|
|
|
|
*(double *) (r->o_buf + i * sizeof (double)) = acc;
|
|
}
|
|
break;
|
|
}
|
|
|
|
r->i_start -= 1.0;
|
|
r->o_buf += r->sample_size;
|
|
r->o_size -= r->sample_size;
|
|
}
|
|
|
|
}
|