diff options
author | David Schleef <ds@schleef.org> | 2005-08-23 19:29:38 +0000 |
---|---|---|
committer | David Schleef <ds@schleef.org> | 2005-08-23 19:29:38 +0000 |
commit | bde8ec9bf7f84427f403755282b45d3994fad7ce (patch) | |
tree | 48577ddcb554ad57e60efc77881eabf63610aff7 | |
parent | 3a9fc486801df3e37e59843dad52022732708105 (diff) | |
download | gst-plugins-bad-bde8ec9bf7f84427f403755282b45d3994fad7ce.tar.gz gst-plugins-bad-bde8ec9bf7f84427f403755282b45d3994fad7ce.tar.bz2 gst-plugins-bad-bde8ec9bf7f84427f403755282b45d3994fad7ce.zip |
gst/audioresample/Makefile.am: Leet audioresampling code
Original commit message from CVS:
* gst/audioresample/Makefile.am: Leet audioresampling code
* gst/audioresample/buffer.c:
* gst/audioresample/buffer.h:
* gst/audioresample/debug.c:
* gst/audioresample/debug.h:
* gst/audioresample/functable.c:
* gst/audioresample/functable.h:
* gst/audioresample/gstaudioresample.c:
* gst/audioresample/gstaudioresample.h:
* gst/audioresample/resample.c:
* gst/audioresample/resample.h:
* gst/audioresample/resample_chunk.c:
* gst/audioresample/resample_functable.c:
* gst/audioresample/resample_ref.c:
-rw-r--r-- | gst/audioresample/Makefile.am | 21 | ||||
-rw-r--r-- | gst/audioresample/buffer.c | 238 | ||||
-rw-r--r-- | gst/audioresample/buffer.h | 48 | ||||
-rw-r--r-- | gst/audioresample/debug.c | 65 | ||||
-rw-r--r-- | gst/audioresample/debug.h | 34 | ||||
-rw-r--r-- | gst/audioresample/functable.c | 254 | ||||
-rw-r--r-- | gst/audioresample/functable.h | 61 | ||||
-rw-r--r-- | gst/audioresample/gstaudioresample.c | 434 | ||||
-rw-r--r-- | gst/audioresample/gstaudioresample.h | 74 | ||||
-rw-r--r-- | gst/audioresample/resample.c | 219 | ||||
-rw-r--r-- | gst/audioresample/resample.h | 114 | ||||
-rw-r--r-- | gst/audioresample/resample_chunk.c | 210 | ||||
-rw-r--r-- | gst/audioresample/resample_functable.c | 272 | ||||
-rw-r--r-- | gst/audioresample/resample_ref.c | 210 |
14 files changed, 2254 insertions, 0 deletions
diff --git a/gst/audioresample/Makefile.am b/gst/audioresample/Makefile.am new file mode 100644 index 00000000..bff05034 --- /dev/null +++ b/gst/audioresample/Makefile.am @@ -0,0 +1,21 @@ + +plugin_LTLIBRARIES = libgstaudioresample.la + +resample_SOURCES = \ + functable.c \ + functable.h \ + resample.c \ + resample_functable.c \ + resample_ref.c \ + resample_chunk.c \ + resample.h \ + debug.c \ + debug.h \ + buffer.c \ + buffer.h + +libgstaudioresample_la_SOURCES = gstaudioresample.c $(resample_SOURCES) +libgstaudioresample_la_CFLAGS = $(GST_CFLAGS) $(LIBOIL_CFLAGS) +libgstaudioresample_la_LIBADD = $(LIBOIL_LIBS) +libgstaudioresample_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + diff --git a/gst/audioresample/buffer.c b/gst/audioresample/buffer.c new file mode 100644 index 00000000..f72e6056 --- /dev/null +++ b/gst/audioresample/buffer.c @@ -0,0 +1,238 @@ + +#ifndef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <audioresample/buffer.h> +#include <glib.h> +#include <string.h> +#include <audioresample/debug.h> + +static void audioresample_buffer_free_mem (AudioresampleBuffer * buffer, + void *); +static void audioresample_buffer_free_subbuffer (AudioresampleBuffer * buffer, + void *priv); + + +AudioresampleBuffer * +audioresample_buffer_new (void) +{ + AudioresampleBuffer *buffer; + + buffer = g_new0 (AudioresampleBuffer, 1); + buffer->ref_count = 1; + return buffer; +} + +AudioresampleBuffer * +audioresample_buffer_new_and_alloc (int size) +{ + AudioresampleBuffer *buffer = audioresample_buffer_new (); + + buffer->data = g_malloc (size); + buffer->length = size; + buffer->free = audioresample_buffer_free_mem; + + return buffer; +} + +AudioresampleBuffer * +audioresample_buffer_new_with_data (void *data, int size) +{ + AudioresampleBuffer *buffer = audioresample_buffer_new (); + + buffer->data = data; + buffer->length = size; + buffer->free = audioresample_buffer_free_mem; + + return buffer; +} + +AudioresampleBuffer * +audioresample_buffer_new_subbuffer (AudioresampleBuffer * buffer, int offset, + int length) +{ + AudioresampleBuffer *subbuffer = audioresample_buffer_new (); + + if (buffer->parent) { + audioresample_buffer_ref (buffer->parent); + subbuffer->parent = buffer->parent; + } else { + audioresample_buffer_ref (buffer); + subbuffer->parent = buffer; + } + subbuffer->data = buffer->data + offset; + subbuffer->length = length; + subbuffer->free = audioresample_buffer_free_subbuffer; + + return subbuffer; +} + +void +audioresample_buffer_ref (AudioresampleBuffer * buffer) +{ + buffer->ref_count++; +} + +void +audioresample_buffer_unref (AudioresampleBuffer * buffer) +{ + buffer->ref_count--; + if (buffer->ref_count == 0) { + if (buffer->free) + buffer->free (buffer, buffer->priv); + g_free (buffer); + } +} + +static void +audioresample_buffer_free_mem (AudioresampleBuffer * buffer, void *priv) +{ + g_free (buffer->data); +} + +static void +audioresample_buffer_free_subbuffer (AudioresampleBuffer * buffer, void *priv) +{ + audioresample_buffer_unref (buffer->parent); +} + + +AudioresampleBufferQueue * +audioresample_buffer_queue_new (void) +{ + return g_new0 (AudioresampleBufferQueue, 1); +} + +int +audioresample_buffer_queue_get_depth (AudioresampleBufferQueue * queue) +{ + return queue->depth; +} + +int +audioresample_buffer_queue_get_offset (AudioresampleBufferQueue * queue) +{ + return queue->offset; +} + +void +audioresample_buffer_queue_free (AudioresampleBufferQueue * queue) +{ + GList *g; + + for (g = g_list_first (queue->buffers); g; g = g_list_next (g)) { + audioresample_buffer_unref ((AudioresampleBuffer *) g->data); + } + g_list_free (queue->buffers); + g_free (queue); +} + +void +audioresample_buffer_queue_push (AudioresampleBufferQueue * queue, + AudioresampleBuffer * buffer) +{ + queue->buffers = g_list_append (queue->buffers, buffer); + queue->depth += buffer->length; +} + +AudioresampleBuffer * +audioresample_buffer_queue_pull (AudioresampleBufferQueue * queue, int length) +{ + GList *g; + AudioresampleBuffer *newbuffer; + AudioresampleBuffer *buffer; + AudioresampleBuffer *subbuffer; + + g_return_val_if_fail (length > 0, NULL); + + if (queue->depth < length) { + return NULL; + } + + RESAMPLE_LOG ("pulling %d, %d available", length, queue->depth); + + g = g_list_first (queue->buffers); + buffer = g->data; + + if (buffer->length > length) { + newbuffer = audioresample_buffer_new_subbuffer (buffer, 0, length); + + subbuffer = audioresample_buffer_new_subbuffer (buffer, length, + buffer->length - length); + g->data = subbuffer; + audioresample_buffer_unref (buffer); + } else { + int offset = 0; + + newbuffer = audioresample_buffer_new_and_alloc (length); + + while (offset < length) { + g = g_list_first (queue->buffers); + buffer = g->data; + + if (buffer->length > length - offset) { + int n = length - offset; + + memcpy (newbuffer->data + offset, buffer->data, n); + subbuffer = + audioresample_buffer_new_subbuffer (buffer, n, buffer->length - n); + g->data = subbuffer; + audioresample_buffer_unref (buffer); + offset += n; + } else { + memcpy (newbuffer->data + offset, buffer->data, buffer->length); + + queue->buffers = g_list_delete_link (queue->buffers, g); + offset += buffer->length; + audioresample_buffer_unref (buffer); + } + } + } + + queue->depth -= length; + queue->offset += length; + + return newbuffer; +} + +AudioresampleBuffer * +audioresample_buffer_queue_peek (AudioresampleBufferQueue * queue, int length) +{ + GList *g; + AudioresampleBuffer *newbuffer; + AudioresampleBuffer *buffer; + int offset = 0; + + g_return_val_if_fail (length > 0, NULL); + + if (queue->depth < length) { + return NULL; + } + + RESAMPLE_LOG ("peeking %d, %d available", length, queue->depth); + + g = g_list_first (queue->buffers); + buffer = g->data; + if (buffer->length > length) { + newbuffer = audioresample_buffer_new_subbuffer (buffer, 0, length); + } else { + newbuffer = audioresample_buffer_new_and_alloc (length); + while (offset < length) { + buffer = g->data; + + if (buffer->length > length - offset) { + int n = length - offset; + + memcpy (newbuffer->data + offset, buffer->data, n); + offset += n; + } else { + memcpy (newbuffer->data + offset, buffer->data, buffer->length); + offset += buffer->length; + } + g = g_list_next (g); + } + } + + return newbuffer; +} diff --git a/gst/audioresample/buffer.h b/gst/audioresample/buffer.h new file mode 100644 index 00000000..17fb5f90 --- /dev/null +++ b/gst/audioresample/buffer.h @@ -0,0 +1,48 @@ + +#ifndef __AUDIORESAMPLE_BUFFER_H__ +#define __AUDIORESAMPLE_BUFFER_H__ + +#include <glib.h> + +typedef struct _AudioresampleBuffer AudioresampleBuffer; +typedef struct _AudioresampleBufferQueue AudioresampleBufferQueue; + +struct _AudioresampleBuffer +{ + unsigned char *data; + int length; + + int ref_count; + + AudioresampleBuffer *parent; + + void (*free) (AudioresampleBuffer *, void *); + void *priv; + void *priv2; +}; + +struct _AudioresampleBufferQueue +{ + GList *buffers; + int depth; + int offset; +}; + +AudioresampleBuffer *audioresample_buffer_new (void); +AudioresampleBuffer *audioresample_buffer_new_and_alloc (int size); +AudioresampleBuffer *audioresample_buffer_new_with_data (void *data, int size); +AudioresampleBuffer *audioresample_buffer_new_subbuffer (AudioresampleBuffer * buffer, int offset, + int length); +void audioresample_buffer_ref (AudioresampleBuffer * buffer); +void audioresample_buffer_unref (AudioresampleBuffer * buffer); + +AudioresampleBufferQueue *audioresample_buffer_queue_new (void); +void audioresample_buffer_queue_free (AudioresampleBufferQueue * queue); +int audioresample_buffer_queue_get_depth (AudioresampleBufferQueue * queue); +int audioresample_buffer_queue_get_offset (AudioresampleBufferQueue * queue); +void audioresample_buffer_queue_push (AudioresampleBufferQueue * queue, + AudioresampleBuffer * buffer); +AudioresampleBuffer *audioresample_buffer_queue_pull (AudioresampleBufferQueue * queue, int len); +AudioresampleBuffer *audioresample_buffer_queue_peek (AudioresampleBufferQueue * queue, int len); + +#endif diff --git a/gst/audioresample/debug.c b/gst/audioresample/debug.c new file mode 100644 index 00000000..27877277 --- /dev/null +++ b/gst/audioresample/debug.c @@ -0,0 +1,65 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib.h> +#include <stdio.h> +#include <debug.h> + +static const char *resample_debug_level_names[] = { + "NONE", + "ERROR", + "WARNING", + "INFO", + "DEBUG", + "LOG" +}; + +static int resample_debug_level = RESAMPLE_LEVEL_ERROR; + +void +resample_debug_log (int level, const char *file, const char *function, + int line, const char *format, ...) +{ +#ifndef GLIB_COMPAT + va_list varargs; + char *s; + + if (level > resample_debug_level) + return; + + va_start (varargs, format); + s = g_strdup_vprintf (format, varargs); + va_end (varargs); + + fprintf (stderr, "RESAMPLE: %s: %s(%d): %s: %s\n", + resample_debug_level_names[level], file, line, function, s); + g_free (s); +#else + va_list varargs; + char s[1000]; + + if (level > resample_debug_level) + return; + + va_start (varargs, format); + vsnprintf (s, 999, format, varargs); + va_end (varargs); + + fprintf (stderr, "RESAMPLE: %s: %s(%d): %s: %s\n", + resample_debug_level_names[level], file, line, function, s); +#endif +} + +void +resample_debug_set_level (int level) +{ + resample_debug_level = level; +} + +int +resample_debug_get_level (void) +{ + return resample_debug_level; +} diff --git a/gst/audioresample/debug.h b/gst/audioresample/debug.h new file mode 100644 index 00000000..2205940c --- /dev/null +++ b/gst/audioresample/debug.h @@ -0,0 +1,34 @@ + +#ifndef __RESAMPLE_DEBUG_H__ +#define __RESAMPLE_DEBUG_H__ + +enum +{ + RESAMPLE_LEVEL_NONE = 0, + RESAMPLE_LEVEL_ERROR, + RESAMPLE_LEVEL_WARNING, + RESAMPLE_LEVEL_INFO, + RESAMPLE_LEVEL_DEBUG, + RESAMPLE_LEVEL_LOG +}; + +#define RESAMPLE_ERROR(...) \ + RESAMPLE_DEBUG_LEVEL(RESAMPLE_LEVEL_ERROR, __VA_ARGS__) +#define RESAMPLE_WARNING(...) \ + RESAMPLE_DEBUG_LEVEL(RESAMPLE_LEVEL_WARNING, __VA_ARGS__) +#define RESAMPLE_INFO(...) \ + RESAMPLE_DEBUG_LEVEL(RESAMPLE_LEVEL_INFO, __VA_ARGS__) +#define RESAMPLE_DEBUG(...) \ + RESAMPLE_DEBUG_LEVEL(RESAMPLE_LEVEL_DEBUG, __VA_ARGS__) +#define RESAMPLE_LOG(...) \ + RESAMPLE_DEBUG_LEVEL(RESAMPLE_LEVEL_LOG, __VA_ARGS__) + +#define RESAMPLE_DEBUG_LEVEL(level,...) \ + resample_debug_log ((level), __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) + +void resample_debug_log (int level, const char *file, const char *function, + int line, const char *format, ...); +void resample_debug_set_level (int level); +int resample_debug_get_level (void); + +#endif diff --git a/gst/audioresample/functable.c b/gst/audioresample/functable.c new file mode 100644 index 00000000..41844015 --- /dev/null +++ b/gst/audioresample/functable.c @@ -0,0 +1,254 @@ +/* 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 <audioresample/functable.h> +#include <audioresample/debug.h> + + + +void +functable_func_sinc (double *fx, double *dfx, double x, void *closure) +{ + if (x == 0) { + *fx = 1; + *dfx = 0; + return; + } + + *fx = sin (x) / x; + *dfx = (cos (x) - sin (x) / x) / x; +} + +void +functable_func_boxcar (double *fx, double *dfx, double x, void *closure) +{ + double width = *(double *) closure; + + if (x < width && x > -width) { + *fx = 1; + } else { + *fx = 0; + } + *dfx = 0; +} + +void +functable_func_hanning (double *fx, double *dfx, double x, void *closure) +{ + double width = *(double *) closure; + + if (x < width && x > -width) { + x /= width; + *fx = (1 - x * x) * (1 - x * x); + *dfx = -2 * 2 * x / width * (1 - x * x); + } else { + *fx = 0; + *dfx = 0; + } +} + + +Functable * +functable_new (void) +{ + Functable *ft; + + ft = malloc (sizeof (Functable)); + memset (ft, 0, sizeof (Functable)); + + return ft; +} + +void +functable_free (Functable * ft) +{ + free (ft); +} + +void +functable_set_length (Functable * t, int length) +{ + t->length = length; +} + +void +functable_set_offset (Functable * t, double offset) +{ + t->offset = offset; +} + +void +functable_set_multiplier (Functable * t, double multiplier) +{ + t->multiplier = multiplier; +} + +void +functable_calculate (Functable * t, FunctableFunc func, void *closure) +{ + int i; + double x; + + if (t->fx) + free (t->fx); + if (t->dfx) + free (t->dfx); + + t->fx = malloc (sizeof (double) * (t->length + 1)); + t->dfx = malloc (sizeof (double) * (t->length + 1)); + + t->inv_multiplier = 1.0 / t->multiplier; + + for (i = 0; i < t->length + 1; i++) { + x = t->offset + t->multiplier * i; + + func (&t->fx[i], &t->dfx[i], x, closure); + } +} + +void +functable_calculate_multiply (Functable * t, FunctableFunc func, void *closure) +{ + int i; + double x; + + for (i = 0; i < t->length + 1; i++) { + double afx, adfx, bfx, bdfx; + + afx = t->fx[i]; + adfx = t->dfx[i]; + x = t->offset + t->multiplier * i; + func (&bfx, &bdfx, x, closure); + t->fx[i] = afx * bfx; + t->dfx[i] = afx * bdfx + adfx * bfx; + } + +} + +double +functable_evaluate (Functable * t, double x) +{ + int i; + double f0, f1, w0, w1; + double x2, x3; + double w; + + if (x < t->offset || x > (t->offset + t->length * t->multiplier)) { + RESAMPLE_DEBUG ("x out of range %g", x); + } + + x -= t->offset; + x *= t->inv_multiplier; + i = floor (x); + x -= i; + + x2 = x * x; + x3 = x2 * x; + + f1 = 3 * x2 - 2 * x3; + f0 = 1 - f1; + w0 = (x - 2 * x2 + x3) * t->multiplier; + w1 = (-x2 + x3) * t->multiplier; + + w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->dfx[i] * w0 + t->dfx[i + 1] * w1; + + /*w = t->fx[i] * (1-x) + t->fx[i+1] * x; */ + + return w; +} + + +double +functable_fir (Functable * t, double x, int n, double *data, int len) +{ + int i, j; + double f0, f1, w0, w1; + double x2, x3; + double w; + double sum; + + x -= t->offset; + x /= t->multiplier; + i = floor (x); + x -= i; + + x2 = x * x; + x3 = x2 * x; + + f1 = 3 * x2 - 2 * x3; + f0 = 1 - f1; + w0 = (x - 2 * x2 + x3) * t->multiplier; + w1 = (-x2 + x3) * t->multiplier; + + sum = 0; + for (j = 0; j < len; j++) { + w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->dfx[i] * w0 + t->dfx[i + 1] * w1; + sum += data[j * 2] * w; + i += n; + } + + return sum; +} + +void +functable_fir2 (Functable * t, double *r0, double *r1, double x, + int n, double *data, int len) +{ + int i, j; + double f0, f1, w0, w1; + double x2, x3; + double w; + double sum0, sum1; + double floor_x; + + x -= t->offset; + x *= t->inv_multiplier; + floor_x = floor (x); + i = floor_x; + x -= floor_x; + + x2 = x * x; + x3 = x2 * x; + + f1 = 3 * x2 - 2 * x3; + f0 = 1 - f1; + w0 = (x - 2 * x2 + x3) * t->multiplier; + w1 = (-x2 + x3) * t->multiplier; + + sum0 = 0; + sum1 = 0; + for (j = 0; j < len; j++) { + w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->dfx[i] * w0 + t->dfx[i + 1] * w1; + sum0 += data[j * 2] * w; + sum1 += data[j * 2 + 1] * w; + i += n; + } + + *r0 = sum0; + *r1 = sum1; +} diff --git a/gst/audioresample/functable.h b/gst/audioresample/functable.h new file mode 100644 index 00000000..4349719d --- /dev/null +++ b/gst/audioresample/functable.h @@ -0,0 +1,61 @@ +/* Resampling library + * Copyright (C) <2001> David 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. + */ + + +#ifndef __FUNCTABLE_H__ +#define __FUNCTABLE_H__ + +typedef void FunctableFunc (double *fx, double *dfx, double x, void *closure); + +typedef struct _Functable Functable; +struct _Functable { + int length; + + double offset; + double multiplier; + + double inv_multiplier; + + double *fx; + double *dfx; +}; + +Functable *functable_new (void); +void functable_setup (Functable *t); +void functable_free (Functable *t); + +void functable_set_length (Functable *t, int length); +void functable_set_offset (Functable *t, double offset); +void functable_set_multiplier (Functable *t, double multiplier); +void functable_calculate (Functable *t, FunctableFunc func, void *closure); +void functable_calculate_multiply (Functable *t, FunctableFunc func, void *closure); + + +double functable_evaluate (Functable *t,double x); + +double functable_fir(Functable *t,double x0,int n,double *data,int len); +void functable_fir2(Functable *t,double *r0, double *r1, double x0, + int n,double *data,int len); + +void functable_func_sinc(double *fx, double *dfx, double x, void *closure); +void functable_func_boxcar(double *fx, double *dfx, double x, void *closure); +void functable_func_hanning(double *fx, double *dfx, double x, void *closure); + +#endif /* __PRIVATE_H__ */ + diff --git a/gst/audioresample/gstaudioresample.c b/gst/audioresample/gstaudioresample.c new file mode 100644 index 00000000..363acd9b --- /dev/null +++ b/gst/audioresample/gstaudioresample.c @@ -0,0 +1,434 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * Copyright (C) 2003,2004 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 (at your option) 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. + */ +/* Element-Checklist-Version: 5 */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <string.h> +#include <math.h> + +/*#define DEBUG_ENABLED */ +#include "gstaudioresample.h" +#include <gst/audio/audio.h> + +GST_DEBUG_CATEGORY_STATIC (audioresample_debug); +#define GST_CAT_DEFAULT audioresample_debug + +/* elementfactory information */ +static GstElementDetails gst_audioresample_details = +GST_ELEMENT_DETAILS ("Audio scaler", + "Filter/Converter/Audio", + "Resample audio", + "David Schleef <ds@schleef.org>"); + +/* Audioresample signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_FILTERLEN +}; + +#define SUPPORTED_CAPS \ + GST_STATIC_CAPS (\ + "audio/x-raw-int, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, MAX ], " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 16, " \ + "depth = (int) 16, " \ + "signed = (boolean) true") + +#if 0 + /* disabled because it segfaults */ +"audio/x-raw-float, " + "rate = (int) [ 1, MAX ], " + "channels = (int) [ 1, MAX ], " + "endianness = (int) BYTE_ORDER, " "width = (int) 32") +#endif + static GstStaticPadTemplate gst_audioresample_sink_template = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS); + + static GstStaticPadTemplate gst_audioresample_src_template = + GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS); + + static void gst_audioresample_base_init (gpointer g_class); + static void gst_audioresample_class_init (AudioresampleClass * klass); + static void gst_audioresample_init (Audioresample * audioresample); + static void gst_audioresample_dispose (GObject * object); + + static void gst_audioresample_chain (GstPad * pad, GstData * _data); + + static void gst_audioresample_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); + static void gst_audioresample_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); + + static GstElementClass *parent_class = NULL; + +/*static guint gst_audioresample_signals[LAST_SIGNAL] = { 0 }; */ + + GType audioresample_get_type (void) + { + static GType audioresample_type = 0; + + if (!audioresample_type) + { + static const GTypeInfo audioresample_info = { + sizeof (AudioresampleClass), + gst_audioresample_base_init, + NULL, + (GClassInitFunc) gst_audioresample_class_init, + NULL, + NULL, + sizeof (Audioresample), 0, + (GInstanceInitFunc) gst_audioresample_init,}; + + audioresample_type = + g_type_register_static (GST_TYPE_ELEMENT, "Audioresample", + &audioresample_info, 0); + } + return audioresample_type; + } + +static void gst_audioresample_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_audioresample_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_audioresample_sink_template)); + + gst_element_class_set_details (gstelement_class, &gst_audioresample_details); +} + +static void gst_audioresample_class_init (AudioresampleClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_audioresample_set_property; + gobject_class->get_property = gst_audioresample_get_property; + gobject_class->dispose = gst_audioresample_dispose; + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FILTERLEN, + g_param_spec_int ("filter_length", "filter_length", "filter_length", + 0, G_MAXINT, 16, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + GST_DEBUG_CATEGORY_INIT (audioresample_debug, "audioresample", 0, + "audioresample element"); +} + +static void gst_audioresample_expand_caps (GstCaps * caps) +{ + gint i; + + for (i = 0; i < gst_caps_get_size (caps); i++) { + GstStructure *structure = gst_caps_get_structure (caps, i); + const GValue *value; + + value = gst_structure_get_value (structure, "rate"); + if (value == NULL) { + GST_ERROR ("caps structure doesn't have required rate field"); + return; + } + + gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, 0); + } +} + +static GstCaps *gst_audioresample_getcaps (GstPad * pad) +{ + Audioresample *audioresample; + GstCaps *caps; + GstPad *otherpad; + + audioresample = GST_AUDIORESAMPLE (gst_pad_get_parent (pad)); + + otherpad = (pad == audioresample->srcpad) ? audioresample->sinkpad : + audioresample->srcpad; + caps = gst_pad_get_allowed_caps (otherpad); + + gst_audioresample_expand_caps (caps); + + return caps; +} + +static GstCaps *gst_audioresample_fixate (GstPad * pad, const GstCaps * caps) +{ + Audioresample *audioresample; + GstPad *otherpad; + int rate; + GstCaps *copy; + GstStructure *structure; + + audioresample = GST_AUDIORESAMPLE (gst_pad_get_parent (pad)); + + if (pad == audioresample->srcpad) { + otherpad = audioresample->sinkpad; + rate = audioresample->i_rate; + } else + { + otherpad = audioresample->srcpad; + rate = audioresample->o_rate; + } + if (!GST_PAD_IS_NEGOTIATING (otherpad)) + return NULL; + if (gst_caps_get_size (caps) > 1) + return NULL; + + copy = gst_caps_copy (caps); + structure = gst_caps_get_structure (copy, 0); + if (rate) { + if (gst_caps_structure_fixate_field_nearest_int (structure, "rate", rate)) { + return copy; + } + } + gst_caps_free (copy); + return NULL; +} + +static GstPadLinkReturn gst_audioresample_link (GstPad * pad, + const GstCaps * caps) +{ + Audioresample *audioresample; + GstStructure *structure; + int rate; + int channels; + gboolean ret; + GstPad *otherpad; + + audioresample = GST_AUDIORESAMPLE (gst_pad_get_parent (pad)); + + otherpad = (pad == audioresample->srcpad) ? audioresample->sinkpad : + audioresample->srcpad; + + structure = gst_caps_get_structure (caps, 0); + ret = gst_structure_get_int (structure, "rate", &rate); + ret &= gst_structure_get_int (structure, "channels", &channels); + if (!ret) + { + return GST_PAD_LINK_REFUSED; + } + + if (gst_pad_is_negotiated (otherpad)) + { + GstCaps *othercaps = gst_caps_copy (caps); + int otherrate; + GstPadLinkReturn linkret; + + if (pad == audioresample->srcpad) { + otherrate = audioresample->i_rate; + } else { + otherrate = audioresample->o_rate; + } + gst_caps_set_simple (othercaps, "rate", G_TYPE_INT, otherrate, NULL); + linkret = gst_pad_try_set_caps (otherpad, othercaps); + if (GST_PAD_LINK_FAILED (linkret)) { + return GST_PAD_LINK_REFUSED; + } + + } + + audioresample->channels = channels; + resample_set_n_channels (audioresample->resample, audioresample->channels); + if (pad == audioresample->srcpad) { + audioresample->o_rate = rate; + resample_set_output_rate (audioresample->resample, audioresample->o_rate); + GST_DEBUG ("set o_rate to %d", rate); + } else { + audioresample->i_rate = rate; + resample_set_input_rate (audioresample->resample, audioresample->i_rate); + GST_DEBUG ("set i_rate to %d", rate); + } + + return GST_PAD_LINK_OK; +} + +static void gst_audioresample_init (Audioresample * audioresample) +{ + ResampleState *r; + + audioresample->sinkpad = + gst_pad_new_from_template (gst_static_pad_template_get + (&gst_audioresample_sink_template), "sink"); + gst_element_add_pad (GST_ELEMENT (audioresample), audioresample->sinkpad); + gst_pad_set_chain_function (audioresample->sinkpad, gst_audioresample_chain); + gst_pad_set_link_function (audioresample->sinkpad, gst_audioresample_link); + gst_pad_set_getcaps_function (audioresample->sinkpad, + gst_audioresample_getcaps); + gst_pad_set_fixate_function (audioresample->sinkpad, + gst_audioresample_fixate); + + audioresample->srcpad = + gst_pad_new_from_template (gst_static_pad_template_get + (&gst_audioresample_src_template), "src"); + + gst_element_add_pad (GST_ELEMENT (audioresample), audioresample->srcpad); + gst_pad_set_link_function (audioresample->srcpad, gst_audioresample_link); + gst_pad_set_getcaps_function (audioresample->srcpad, + gst_audioresample_getcaps); + gst_pad_set_fixate_function (audioresample->srcpad, gst_audioresample_fixate); + + r = resample_new (); + audioresample->resample = r; + + resample_set_filter_length (r, 64); + resample_set_format (r, RESAMPLE_FORMAT_S16); +} + +static void gst_audioresample_dispose (GObject * object) +{ + Audioresample *audioresample = GST_AUDIORESAMPLE (object); + + if (audioresample->resample) { + resample_free (audioresample->resample); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void gst_audioresample_chain (GstPad * pad, GstData * _data) +{ + GstBuffer *buf = GST_BUFFER (_data); + Audioresample *audioresample; + ResampleState *r; + guchar *data; + gulong size; + int outsize; + GstBuffer *outbuf; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + + audioresample = GST_AUDIORESAMPLE (gst_pad_get_parent (pad)); + + if (!GST_IS_BUFFER (_data)) { + gst_pad_push (audioresample->srcpad, _data); + return; + } + + if (audioresample->passthru) { + gst_pad_push (audioresample->srcpad, GST_DATA (buf)); + return; + } + + r = audioresample->resample; + + data = GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + GST_DEBUG ("got buffer of %ld bytes", size); + + resample_add_input_data (r, data, size, (ResampleCallback) gst_data_unref, + buf); + + outsize = resample_get_output_size (r); + /* FIXME this is audioresample being dumb. dunno why */ + if (outsize == 0) { + GST_ERROR ("overriding outbuf size"); + outsize = size; + } + outbuf = gst_buffer_new_and_alloc (outsize); + + outsize = resample_get_output_data (r, GST_BUFFER_DATA (outbuf), outsize); + GST_BUFFER_SIZE (outbuf) = outsize; + + GST_BUFFER_TIMESTAMP (outbuf) = + audioresample->offset * GST_SECOND / audioresample->o_rate; + audioresample->offset += outsize / sizeof (gint16) / audioresample->channels; + + gst_pad_push (audioresample->srcpad, GST_DATA (outbuf)); +} + +static void + gst_audioresample_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + Audioresample *audioresample; + + g_return_if_fail (GST_IS_AUDIORESAMPLE (object)); + audioresample = GST_AUDIORESAMPLE (object); + + switch (prop_id) { + case ARG_FILTERLEN: + audioresample->filter_length = g_value_get_int (value); + GST_DEBUG_OBJECT (GST_ELEMENT (audioresample), "new filter length %d\n", + audioresample->filter_length); + resample_set_filter_length (audioresample->resample, + audioresample->filter_length); + break; + default:G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void + gst_audioresample_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + Audioresample *audioresample; + + g_return_if_fail (GST_IS_AUDIORESAMPLE (object)); + audioresample = GST_AUDIORESAMPLE (object); + + switch (prop_id) { + case ARG_FILTERLEN: + g_value_set_int (value, audioresample->filter_length); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static gboolean plugin_init (GstPlugin * plugin) +{ + resample_init (); + + if (!gst_element_register (plugin, "audioresample", GST_RANK_PRIMARY, + GST_TYPE_AUDIORESAMPLE)) { + return FALSE; + } + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "audioresample", + "Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN) diff --git a/gst/audioresample/gstaudioresample.h b/gst/audioresample/gstaudioresample.h new file mode 100644 index 00000000..fc5115da --- /dev/null +++ b/gst/audioresample/gstaudioresample.h @@ -0,0 +1,74 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * 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 (at your option) 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. + */ + + +#ifndef __AUDIORESAMPLE_H__ +#define __AUDIORESAMPLE_H__ + + +#include <gst/gst.h> + +#include <audioresample/resample.h> + + +G_BEGIN_DECLS + + +#define GST_TYPE_AUDIORESAMPLE \ + (audioresample_get_type()) +#define GST_AUDIORESAMPLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIORESAMPLE,Audioresample)) +#define GST_AUDIORESAMPLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIORESAMPLE,Audioresample)) +#define GST_IS_AUDIORESAMPLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIORESAMPLE)) +#define GST_IS_AUDIORESAMPLE_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIORESAMPLE)) + +typedef struct _Audioresample Audioresample; +typedef struct _AudioresampleClass AudioresampleClass; + +struct _Audioresample { + GstElement element; + + GstPad *sinkpad,*srcpad; + + gboolean passthru; + + gint64 offset; + int channels; + + int i_rate; + int o_rate; + int filter_length; + + ResampleState * resample; +}; + +struct _AudioresampleClass { + GstElementClass parent_class; +}; + +GType gst_audioresample_get_type(void); + + +G_END_DECLS + + +#endif /* __AUDIORESAMPLE_H__ */ diff --git a/gst/audioresample/resample.c b/gst/audioresample/resample.c new file mode 100644 index 00000000..38c6ba84 --- /dev/null +++ b/gst/audioresample/resample.c @@ -0,0 +1,219 @@ +/* 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 <audioresample/resample.h> +#include <audioresample/buffer.h> +#include <audioresample/debug.h> + +void resample_scale_ref (ResampleState * r); +void resample_scale_functable (ResampleState * r); + + + +void +resample_init (void) +{ + static int inited = 0; + + if (!inited) { + oil_init (); + inited = 1; + } +} + +ResampleState * +resample_new (void) +{ + ResampleState *r; + + r = malloc (sizeof (ResampleState)); + memset (r, 0, sizeof (ResampleState)); + + r->filter_length = 16; + + r->i_start = 0; + if (r->filter_length & 1) { + r->o_start = 0; + } else { + r->o_start = r->o_inc * 0.5; + } + + r->queue = audioresample_buffer_queue_new (); + r->out_tmp = malloc (10000 * sizeof (double)); + + r->need_reinit = 1; + + return r; +} + +void +resample_free (ResampleState * r) +{ + if (r->buffer) { + free (r->buffer); + } + if (r->ft) { + functable_free (r->ft); + } + if (r->queue) { + audioresample_buffer_queue_free (r->queue); + } + if (r->out_tmp) { + free (r->out_tmp); + } + + free (r); +} + +static void +resample_buffer_free (AudioresampleBuffer * buffer, void *priv) +{ + if (buffer->priv2) { + ((void (*)(void *)) buffer->priv2) (buffer->priv); + } +} + +void +resample_add_input_data (ResampleState * r, void *data, int size, + void (*free_func) (void *), void *closure) +{ + AudioresampleBuffer *buffer; + + RESAMPLE_DEBUG ("data %p size %d", data, size); + + buffer = audioresample_buffer_new_with_data (data, size); + buffer->free = resample_buffer_free; + buffer->priv2 = free_func; + buffer->priv = closure; + + audioresample_buffer_queue_push (r->queue, buffer); +} + +void +resample_input_eos (ResampleState * r) +{ + AudioresampleBuffer *buffer; + int sample_size; + + sample_size = r->n_channels * resample_format_size (r->format); + + buffer = audioresample_buffer_new_and_alloc (sample_size * + (r->filter_length / 2)); + memset (buffer->data, 0, buffer->length); + + audioresample_buffer_queue_push (r->queue, buffer); + + r->eos = 1; +} + +int +resample_get_output_size (ResampleState * r) +{ + return floor (audioresample_buffer_queue_get_depth (r->queue) * r->o_rate / + r->i_rate); +} + +int +resample_get_output_data (ResampleState * r, void *data, int size) +{ + r->o_buf = data; + r->o_size = size; + + switch (r->method) { + case 0: + resample_scale_ref (r); + break; + case 1: + resample_scale_functable (r); + break; + default: + break; + } + + return size - r->o_size; +} + +void +resample_set_filter_length (ResampleState * r, int length) +{ + r->filter_length = length; + r->need_reinit = 1; +} + +void +resample_set_input_rate (ResampleState * r, double rate) +{ + r->i_rate = rate; + r->need_reinit = 1; +} + +void +resample_set_output_rate (ResampleState * r, double rate) +{ + r->o_rate = rate; + r->need_reinit = 1; +} + +void +resample_set_n_channels (ResampleState * r, int n_channels) +{ + r->n_channels = n_channels; + r->need_reinit = 1; +} + +void +resample_set_format (ResampleState * r, ResampleFormat format) +{ + r->format = format; + r->need_reinit = 1; +} + +void +resample_set_method (ResampleState * r, int method) +{ + r->method = method; + r->need_reinit = 1; +} + +int +resample_format_size (ResampleFormat format) +{ + switch (format) { + case RESAMPLE_FORMAT_S16: + return 2; + case RESAMPLE_FORMAT_S32: + case RESAMPLE_FORMAT_F32: + return 4; + case RESAMPLE_FORMAT_F64: + return 8; + } + return 0; +} diff --git a/gst/audioresample/resample.h b/gst/audioresample/resample.h new file mode 100644 index 00000000..9be54f46 --- /dev/null +++ b/gst/audioresample/resample.h @@ -0,0 +1,114 @@ +/* Resampling library + * Copyright (C) <2001> David 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. + */ + + +#ifndef __RESAMPLE_H__ +#define __RESAMPLE_H__ + +#include <audioresample/functable.h> +#include <audioresample/buffer.h> + +typedef enum { + RESAMPLE_FORMAT_S16 = 0, + RESAMPLE_FORMAT_S32, + RESAMPLE_FORMAT_F32, + RESAMPLE_FORMAT_F64 +} ResampleFormat; + +typedef void (*ResampleCallback) (void *); + +typedef struct _ResampleState ResampleState; + +struct _ResampleState { + /* parameters */ + + int n_channels; + ResampleFormat format; + + int filter_length; + + double i_rate; + double o_rate; + + int method; + + /* internal parameters */ + + int need_reinit; + + double halftaps; + + /* filter state */ + + void *o_buf; + int o_size; + + AudioresampleBufferQueue *queue; + int eos; + int started; + + int sample_size; + + void *buffer; + int buffer_len; + + double i_start; + double o_start; + + double i_inc; + double o_inc; + + double sinc_scale; + + double i_end; + double o_end; + + int i_samples; + int o_samples; + + //void *i_buf; + + Functable *ft; + + double *out_tmp; +}; + +void resample_init(void); +void resample_cleanup(void); + +ResampleState *resample_new (void); +void resample_free (ResampleState *state); + +void resample_add_input_data (ResampleState * r, void *data, int size, + ResampleCallback free_func, void *closure); +void resample_input_eos (ResampleState *r); +int resample_get_output_size (ResampleState *r); +int resample_get_output_data (ResampleState *r, void *data, int size); + +void resample_set_filter_length (ResampleState *r, int length); +void resample_set_input_rate (ResampleState *r, double rate); +void resample_set_output_rate (ResampleState *r, double rate); +void resample_set_n_channels (ResampleState *r, int n_channels); +void resample_set_format (ResampleState *r, ResampleFormat format); +void resample_set_method (ResampleState *r, int method); +int resample_format_size (ResampleFormat format); + + +#endif /* __RESAMPLE_H__ */ + diff --git a/gst/audioresample/resample_chunk.c b/gst/audioresample/resample_chunk.c new file mode 100644 index 00000000..53755e62 --- /dev/null +++ b/gst/audioresample/resample_chunk.c @@ -0,0 +1,210 @@ +/* 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 <audioresample/resample.h> +#include <audioresample/buffer.h> +#include <audioresample/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) { + r->sample_size = r->n_channels * resample_format_size (r->format); + 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; + } + +} diff --git a/gst/audioresample/resample_functable.c b/gst/audioresample/resample_functable.c new file mode 100644 index 00000000..af5f9253 --- /dev/null +++ b/gst/audioresample/resample_functable.c @@ -0,0 +1,272 @@ +/* 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 <audioresample/resample.h> +#include <audioresample/buffer.h> +#include <audioresample/debug.h> + +static void +func_sinc (double *fx, double *dfx, double x, void *closure) +{ + //double scale = *(double *)closure; + double scale = M_PI; + + if (x == 0) { + *fx = 1; + *dfx = 0; + return; + } + + x *= scale; + *fx = sin (x) / x; + *dfx = scale * (cos (x) - sin (x) / x) / x; +} + +static void +func_hanning (double *fx, double *dfx, double x, void *closure) +{ + double width = *(double *) closure; + + if (x < width && x > -width) { + x /= width; + *fx = (1 - x * x) * (1 - x * x); + *dfx = -2 * 2 * x / width * (1 - x * x); + } else { + *fx = 0; + *dfx = 0; + } +} + +#if 0 +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; +} +#endif + +#if 0 +static void +functable_test (Functable * ft, double halfwidth) +{ + int i; + double x; + + for (i = 0; i < 100; i++) { + x = i * 0.1; + printf ("%d %g %g\n", i, resample_sinc_window (x, halfwidth, 1.0), + functable_evaluate (ft, x)); + } + exit (0); + +} +#endif + + +void +resample_scale_functable (ResampleState * r) +{ + if (r->need_reinit) { + double hanning_width; + + r->sample_size = r->n_channels * resample_format_size (r->format); + RESAMPLE_DEBUG ("sample size %d", r->sample_size); + + if (r->buffer) + free (r->buffer); + r->buffer_len = r->sample_size * r->filter_length; + 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; + + if (r->ft) { + functable_free (r->ft); + } + r->ft = functable_new (); + functable_set_length (r->ft, r->filter_length * 16); + functable_set_offset (r->ft, -r->filter_length / 2); + functable_set_multiplier (r->ft, 1 / 16.0); + + hanning_width = r->filter_length / 2; + functable_calculate (r->ft, func_sinc, NULL); + functable_calculate_multiply (r->ft, func_hanning, &hanning_width); + + //functable_test(r->ft, 0.5 * r->filter_length); +#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 + + r->need_reinit = 0; + } + + 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 += functable_evaluate (r->ft, offset) * x; + //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 += functable_evaluate (r->ft, offset) * x; + //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 += functable_evaluate (r->ft, offset) * x; + //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 += functable_evaluate (r->ft, offset) * x; + //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; + } + +} diff --git a/gst/audioresample/resample_ref.c b/gst/audioresample/resample_ref.c new file mode 100644 index 00000000..a4623e71 --- /dev/null +++ b/gst/audioresample/resample_ref.c @@ -0,0 +1,210 @@ +/* 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 <audioresample/resample.h> +#include <audioresample/buffer.h> +#include <audioresample/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_ref (ResampleState * r) +{ + if (r->need_reinit) { + r->sample_size = r->n_channels * resample_format_size (r->format); + RESAMPLE_DEBUG ("sample size %d", r->sample_size); + + if (r->buffer) + free (r->buffer); + r->buffer_len = r->sample_size * r->filter_length; + 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; + } + +} |