summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDavid Schleef <ds@schleef.org>2006-12-13 10:08:27 +0000
committerDavid Schleef <ds@schleef.org>2006-12-13 10:08:27 +0000
commit03e7e4a2f766cfb102745d07b78edad1b9c34554 (patch)
treeacf37397acb32932d27bf0f164b54672218f5e69 /examples
parent495ec7b85bd093f38668e1b1923f1a65069720b2 (diff)
downloadliboil-03e7e4a2f766cfb102745d07b78edad1b9c34554.tar.gz
* configure.ac:
* examples/Makefile.am: * examples/audioresample/Makefile.am: * examples/audioresample/buffer.c: * examples/audioresample/buffer.h: * examples/audioresample/functable.c: * examples/audioresample/functable.h: * examples/audioresample/resample-removed.c: * examples/audioresample/resample.c: * examples/audioresample/resample.h: * examples/audioresample/resample_chunk.c: * examples/audioresample/resample_functable.c: * examples/audioresample/resample_ref.c: * examples/audioresample/test_functable1.c: Copied from elsewhere and hacked up.
Diffstat (limited to 'examples')
-rw-r--r--examples/Makefile.am2
-rw-r--r--examples/audioresample/Makefile.am22
-rw-r--r--examples/audioresample/buffer.c261
-rw-r--r--examples/audioresample/buffer.h74
-rw-r--r--examples/audioresample/functable.c255
-rw-r--r--examples/audioresample/functable.h64
-rw-r--r--examples/audioresample/resample-removed.c768
-rw-r--r--examples/audioresample/resample.c226
-rw-r--r--examples/audioresample/resample.h121
-rw-r--r--examples/audioresample/resample_chunk.c200
-rw-r--r--examples/audioresample/resample_functable.c271
-rw-r--r--examples/audioresample/resample_ref.c200
-rw-r--r--examples/audioresample/test_functable1.c289
13 files changed, 2752 insertions, 1 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am
index b683bb4..f66348b 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -1,5 +1,5 @@
-SUBDIRS = jpeg md5 uberopt work huffman taylor videoscale
+SUBDIRS = jpeg md5 uberopt work huffman taylor videoscale audioresample
bin_PROGRAMS = oil-bugreport
diff --git a/examples/audioresample/Makefile.am b/examples/audioresample/Makefile.am
new file mode 100644
index 0000000..811acb3
--- /dev/null
+++ b/examples/audioresample/Makefile.am
@@ -0,0 +1,22 @@
+
+noinst_PROGRAMS = test_functable1
+
+noinst_LTLIBRARIES = libaudioresample.la
+#noinst_PROGRAMS = audioresample_test
+
+libaudioresample_la_SOURCES = buffer.c functable.c
+ resample-removed.c resample.c resample_chunk.c \
+ resample_functable.c resample_ref.c
+libaudioresample_la_CFLAGS = $(LIBOIL_CFLAGS) $(GLIB_CFLAGS)
+
+noinst_HEADERS = buffer.h functable.h resample.h
+
+
+#audioresample_test_SOURCES = test.c
+#audioresample_test_CFLAGS = $(LIBOIL_CFLAGS)
+#audioresample_test_LDADD = libaudioresample.la $(LIBOIL_LIBS)
+
+test_functable1_SOURCES = test_functable1.c
+test_functable1_CFLAGS = $(LIBOIL_CFLAGS)
+test_functable1_LDADD = libaudioresample.la $(LIBOIL_LIBS)
+
diff --git a/examples/audioresample/buffer.c b/examples/audioresample/buffer.c
new file mode 100644
index 0000000..219fbda
--- /dev/null
+++ b/examples/audioresample/buffer.c
@@ -0,0 +1,261 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+#include <string.h>
+#include <liboil/liboildebug.h>
+
+#include "buffer.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;
+ }
+
+ OIL_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;
+ }
+
+ OIL_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/examples/audioresample/buffer.h b/examples/audioresample/buffer.h
new file mode 100644
index 0000000..d4246c2
--- /dev/null
+++ b/examples/audioresample/buffer.h
@@ -0,0 +1,74 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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/examples/audioresample/functable.c b/examples/audioresample/functable.c
new file mode 100644
index 0000000..b01760b
--- /dev/null
+++ b/examples/audioresample/functable.c
@@ -0,0 +1,255 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <liboil/liboildebug.h>
+
+#include "functable.h"
+
+
+
+void
+functable_function_sinc(double *fx, double *dfx, double x,
+ double param1, double param2)
+{
+ if(x==0){
+ *fx = 1;
+ *dfx = 0;
+ return;
+ }
+
+ *fx = sin(x)/x;
+ *dfx = (cos(x) - sin(x)/x)/x;
+}
+
+void
+functable_function_boxcar(double *fx, double *dfx, double x,
+ double param1, double param2)
+{
+ double width = param1;
+
+ if (x < width && x > -width) {
+ *fx = 1;
+ } else {
+ *fx = 0;
+ }
+ *dfx = 0;
+}
+
+void
+functable_function_hanning(double *fx, double *dfx, double x,
+ double param1, double param2)
+{
+ double width = param1;
+
+ 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 (int length, int oversample, double offset, double multiplier)
+{
+ Functable *ft;
+
+ ft = malloc (sizeof(Functable));
+ memset (ft, 0, sizeof(Functable));
+
+ ft->length = length;
+ ft->offset = offset;
+ ft->multiplier = multiplier;
+ ft->oversample = oversample;
+
+ ft->inv_multiplier = 1.0 / ft->multiplier;
+ ft->submultiplier = ft->multiplier / ft->oversample;
+ ft->inv_submultiplier = 1.0 / ft->submultiplier;
+
+ ft->fx = malloc(sizeof(double)*ft->length*(ft->oversample + 1));
+ ft->dfx = malloc(sizeof(double)*ft->length*(ft->oversample + 1));
+
+ memset (ft->fx, 0, sizeof(double)*ft->length*(ft->oversample + 1));
+ memset (ft->dfx, 0, sizeof(double)*ft->length*(ft->oversample + 1));
+
+ return ft;
+}
+
+void
+functable_free (Functable *ft)
+{
+ free (ft->fx);
+ free (ft->dfx);
+ free (ft);
+}
+
+void
+functable_calculate (Functable *t, FunctableFunc func, double param1,
+ double param2)
+{
+ int i, j;
+ double x;
+ double *fx;
+ double *dfx;
+
+ for(j=0;j<t->oversample + 1;j++){
+ fx = t->fx + t->length*j;
+ dfx = t->dfx + t->length*j;
+ for(i=0;i<t->length;i++){
+ x = t->offset + t->submultiplier * (i * t->oversample + j);
+
+ func (&fx[i], &dfx[i], x, param1, param2);
+ dfx[i] *= t->submultiplier;
+ }
+ }
+}
+
+void
+functable_calculate_multiply (Functable *t, FunctableFunc func,
+ double param1, double param2)
+{
+ int i;
+ int j;
+ double x;
+ double *fx;
+ double *dfx;
+ double afx, dafx, bfx, dbfx;
+
+ for(j=0;j<t->oversample + 1;j++){
+ fx = t->fx + t->length*j;
+ dfx = t->dfx + t->length*j;
+ for(i=0;i<t->length;i++){
+ x = t->offset + t->submultiplier * (i * t->oversample + j);
+
+ afx = fx[i];
+ dafx = dfx[i];
+ func (&bfx, &dbfx, x, param1, param2);
+ fx[i] = afx * bfx;
+ dfx[i] = afx * dbfx + dafx * bfx;
+ }
+ }
+}
+
+double
+functable_evaluate (Functable *t, double x)
+{
+ int i, j;
+ double f0, f1, w0, w1;
+ double x2, x3;
+ double w;
+ double *fx1, *fx2;
+ double *dfx1, *dfx2;
+ int xi;
+
+ if(x<t->offset || x>(t->offset+t->length*t->multiplier)){
+ OIL_DEBUG ("x out of range %g",x);
+ return 0;
+ }
+
+ x -= t->offset;
+ x *= t->inv_submultiplier;
+ xi = floor(x);
+ j = xi % t->oversample;
+ i = xi / t->oversample;
+ x -= xi;
+
+ fx1 = t->fx + j*t->length;
+ fx2 = t->fx + (j+1)*t->length;
+ dfx1 = t->dfx + j*t->length;
+ dfx2 = t->dfx + (j+1)*t->length;
+
+ x2 = x * x;
+ x3 = x2 * x;
+
+ f1 = 3 * x2 - 2 * x3;
+ f0 = 1 - f1;
+ w0 = x - 2 * x2 + x3;
+ w1 = -x2 + x3;
+
+ w = fx1[i] * f0 + fx2[i] * f1 + dfx1[i] * w0 + dfx2[i] * w1;
+
+ return w;
+}
+
+double
+functable_mult_and_sum (Functable *t, double x, double *data, int n)
+{
+ int i, j;
+ double f0, f1, w0, w1;
+ double x2, x3;
+ double w;
+ double *fx1, *fx2;
+ double *dfx1, *dfx2;
+ int xi;
+ double sum;
+
+ if(x<t->offset || x>(t->offset+t->length*t->multiplier)){
+ OIL_DEBUG ("x out of range %g",x);
+ return 0;
+ }
+
+ x -= t->offset;
+ x *= t->inv_submultiplier;
+ xi = floor(x);
+ j = xi % t->oversample;
+ i = xi / t->oversample;
+ x -= xi;
+
+ fx1 = t->fx + j*t->length + i;
+ fx2 = t->fx + (j+1)*t->length + i;
+ dfx1 = t->dfx + j*t->length + i;
+ dfx2 = t->dfx + (j+1)*t->length + i;
+
+ x2 = x * x;
+ x3 = x2 * x;
+
+ f1 = 3 * x2 - 2 * x3;
+ f0 = 1 - f1;
+ w0 = x - 2 * x2 + x3;
+ w1 = -x2 + x3;
+
+ sum = 0;
+ for(i=0;i<n;i++){
+ w = fx1[i] * f0 + fx2[i] * f1 + dfx1[i] * w0 + dfx2[i] * w1;
+ sum += w * data[i];
+ }
+
+ return sum;
+}
+
+
diff --git a/examples/audioresample/functable.h b/examples/audioresample/functable.h
new file mode 100644
index 0000000..f2dc88b
--- /dev/null
+++ b/examples/audioresample/functable.h
@@ -0,0 +1,64 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FUNCTABLE_H__
+#define __FUNCTABLE_H__
+
+typedef void FunctableFunc (double *fx, double *dfx, double x, double param1,
+ double param2);
+
+typedef struct _Functable Functable;
+struct _Functable {
+ int length;
+ int oversample;
+
+ double offset;
+ double multiplier;
+
+ double submultiplier;
+ double inv_multiplier;
+ double inv_submultiplier;
+
+ double *fx;
+ double *dfx;
+};
+
+Functable *functable_new (int length, int oversample, double offset, double multiplier);
+void functable_free (Functable *t);
+
+void functable_calculate (Functable *t, FunctableFunc func, double param1, double param2);
+void functable_calculate_multiply (Functable *t, FunctableFunc func, double param1, double param2);
+
+double functable_evaluate (Functable *t, double x);
+double functable_mult_and_sum (Functable *t, double x0, double *data, int n);
+
+FunctableFunc functable_function_sinc;
+FunctableFunc functable_function_boxcar;
+FunctableFunc functable_function_hanning;
+
+#endif /* __FUNCTABLE_H__ */
+
diff --git a/examples/audioresample/resample-removed.c b/examples/audioresample/resample-removed.c
new file mode 100644
index 0000000..6d00d4f
--- /dev/null
+++ b/examples/audioresample/resample-removed.c
@@ -0,0 +1,768 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <liboil/liboil.h>
+
+#include <audioresample/resample.h>
+#include <audioresample/buffer.h>
+#include <audioresample/debug.h>
+
+static void resample_scale (ResampleState * r);
+static void resample_scale_ref (ResampleState * r);
+//static void resample_scale_2 (ResampleState * r);
+//static void resample_sinc (ResampleState * r);
+static void resample_sinc_ft (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);
+}
+
+#if 0
+void
+resample_setup (ResampleState * r)
+{
+ /* i_inc is the number of samples that the output increments for
+ * each input sample. o_inc is the opposite. */
+ r->i_inc = (double) r->o_rate / r->i_rate;
+ r->o_inc = (double) r->i_rate / r->o_rate;
+
+ r->halftaps = (r->filter_length - 1.0) * 0.5;
+
+ if (r->format == RESAMPLE_FORMAT_S16) {
+ r->sample_size = 2;
+ } else if (r->format == RESAMPLE_FORMAT_F32) {
+ r->sample_size = 4;
+ } else {
+ OIL_ERROR ("Unexpected format \"%d\"", r->format);
+ }
+}
+#endif
+
+static void
+resample_buffer_free(AudioresampleBuffer *buffer, void *priv)
+{
+ ((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;
+
+ OIL_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 (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;
+}
+
+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;
+}
+
+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;
+}
+
+static void
+resample_scale_ref (ResampleState * r)
+{
+ if (r->need_reinit) {
+ r->sample_size = r->n_channels * resample_format_size(r->format);
+ //OIL_ERROR("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;
+ //OIL_ERROR("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;
+
+ //OIL_ERROR("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) {
+ OIL_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) {
+ OIL_ERROR("buffer_queue_pull returned NULL");
+ return;
+ }
+
+ r->i_start += r->i_inc;
+ //OIL_ERROR("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;
+ }
+ /* FIXME */
+ //if(acc<32768.0)acc=-32768.0;
+ //if(acc>32767.0)acc=32767.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)) = rint(acc);
+ }
+ break;
+ }
+
+ r->i_start -= 1.0;
+ r->o_buf += r->sample_size;
+ r->o_size -= r->sample_size;
+ }
+
+}
+
+#if 0
+static void
+resample_scale_2 (ResampleState * r)
+{
+ /* only downsamples by a factor of 2, with no filtering */
+
+ while(r->o_size > 0) {
+ AudioresampleBuffer *buffer;
+
+ buffer = audioresample_buffer_queue_pull (r->queue, 2 * r->sample_size);
+ if (buffer == NULL) {
+ return;
+ }
+
+ memcpy(r->o_buf, buffer->data, r->sample_size);
+
+ r->o_buf += r->sample_size;
+ r->o_size -= r->sample_size;
+ }
+
+}
+#endif
+
+/*
+ * Prepare to be confused.
+ *
+ * We keep a "timebase" that is based on output samples. The zero
+ * of the timebase corresponds to the next output sample that will
+ * be written.
+ *
+ * i_start is the "time" that corresponds to the first input sample
+ * in an incoming buffer. Since the output depends on input samples
+ * ahead in time, i_start will tend to be around halftaps.
+ *
+ * i_start_buf is the time of the first sample in the temporary
+ * buffer.
+ */
+static void
+resample_scale (ResampleState * r)
+{
+ int o_size;
+
+ r->i_samples = 100 / r->sample_size / r->n_channels;
+
+ //r->i_start_buf = r->i_start - r->filter_length * r->i_inc;
+
+ /* i_start is the offset (in a given output sample) that is the
+ * beginning of the current input buffer */
+ r->i_end = r->i_start + r->i_inc * r->i_samples;
+
+ r->o_samples = floor (r->i_end - r->halftaps * r->i_inc);
+
+ o_size = r->o_samples * r->n_channels * r->sample_size;
+
+ OIL_DEBUG ("i_samples=%d o_samples=%d i_inc=%g o_buf=%p",
+ r->i_samples, r->o_samples, r->i_inc, r->o_buf);
+ OIL_DEBUG ("resample_scale: i_start=%g i_end=%g o_start=%g",
+ r->i_start, r->i_end, r->o_start);
+
+ if ((r->filter_length + r->i_samples) * r->sample_size * r->n_channels >
+ r->buffer_len) {
+ int size = (r->filter_length + r->i_samples) * sizeof (double) * 2;
+
+ OIL_DEBUG ("resample temp buffer size=%d", size);
+ if (r->buffer)
+ free (r->buffer);
+ r->buffer_len = size;
+ r->buffer = malloc (size);
+ memset (r->buffer, 0, size);
+ }
+
+ if (r->format == RESAMPLE_FORMAT_S16) {
+ if (r->n_channels == 2) {
+ oil_conv_f64_s16 (r->buffer + r->filter_length * sizeof (double) * 2,
+ sizeof (double), r->i_buf, sizeof (short), r->i_samples * 2);
+ } else {
+ oil_conv_f64_s16 (r->buffer + r->filter_length * sizeof (double) * 2,
+ sizeof (double) * 2, r->i_buf, sizeof (short), r->i_samples);
+ }
+ } else if (r->format == RESAMPLE_FORMAT_F32) {
+ if (r->n_channels == 2) {
+ oil_conv_f64_f32 (r->buffer + r->filter_length * sizeof (double) * 2,
+ sizeof (double), r->i_buf, sizeof (float), r->i_samples * 2);
+ } else {
+ oil_conv_f64_f32 (r->buffer + r->filter_length * sizeof (double) * 2,
+ sizeof (double) * 2, r->i_buf, sizeof (float), r->i_samples);
+ }
+ }
+
+ resample_sinc_ft (r);
+
+ if (r->format == RESAMPLE_FORMAT_S16) {
+ if (r->n_channels == 2) {
+ oil_conv_s16_f64 (r->o_buf, sizeof(short), r->out_tmp, sizeof(double),
+ 2 * r->o_samples);
+ } else {
+ oil_conv_s16_f64 (r->o_buf, sizeof(short), r->out_tmp, sizeof(double) * 2,
+ r->o_samples);
+ }
+ } else if (r->format == RESAMPLE_FORMAT_F32) {
+ if (r->n_channels == 2) {
+ oil_conv_f32_f64 (r->o_buf, sizeof(float), r->out_tmp, sizeof(double),
+ 2 * r->o_samples);
+ } else {
+ oil_conv_f32_f64 (r->o_buf, sizeof(float), r->out_tmp, sizeof(double) * 2,
+ r->o_samples);
+ }
+ }
+
+ memcpy (r->buffer,
+ r->buffer + r->i_samples * sizeof (double) * 2,
+ r->filter_length * sizeof (double) * 2);
+
+ /* updating times */
+ r->i_start += r->i_samples * r->i_inc;
+ r->o_start += r->o_samples * r->o_inc - r->i_samples;
+
+ /* adjusting timebase zero */
+ r->i_start -= r->o_samples;
+}
+
+#if 0
+static void
+resample_sinc_slow (ResampleState * r)
+{
+ signed short *i_ptr, *o_ptr;
+ int i, j;
+ double c0, c1;
+ double a;
+ int start;
+ double center;
+ double weight;
+
+ if (!r->buffer) {
+ int size = r->filter_length * 2 * r->n_channels;
+
+ OIL_DEBUG ("resample temp buffer");
+ r->buffer = malloc (size);
+ memset (r->buffer, 0, size);
+ }
+
+ i_ptr = (signed short *) r->i_buf;
+ o_ptr = (signed short *) r->o_buf;
+
+ a = r->i_start;
+#define GETBUF(index,chan) (((index)<0) \
+ ? ((short *)(r->buffer))[((index)+r->filter_length)*2+(chan)] \
+ : i_ptr[(index)*2+(chan)])
+ {
+ double sinx, cosx, sind, cosd;
+ double x, d;
+ double t;
+
+ for (i = 0; i < r->o_samples; i++) {
+ start = floor (a) - r->filter_length;
+ center = a - r->halftaps;
+ x = M_PI * (start - center) * r->o_inc;
+ sinx = sin (M_PI * (start - center) * r->o_inc);
+ cosx = cos (M_PI * (start - center) * r->o_inc);
+ d = M_PI * r->o_inc;
+ sind = sin (M_PI * r->o_inc);
+ cosd = cos (M_PI * r->o_inc);
+ c0 = 0;
+ c1 = 0;
+ for (j = 0; j < r->filter_length; j++) {
+ weight = (x == 0) ? 1 : (sinx / x);
+ c0 += weight * GETBUF ((start + j), 0);
+ c1 += weight * GETBUF ((start + j), 1);
+ t = cosx * cosd - sinx * sind;
+ sinx = cosx * sind + sinx * cosd;
+ cosx = t;
+ x += d;
+ }
+ o_ptr[0] = rint (c0);
+ o_ptr[1] = rint (c1);
+ o_ptr += 2;
+ a += r->o_inc;
+ }
+ }
+#undef GETBUF
+
+ memcpy (r->buffer,
+ i_ptr + (r->i_samples - r->filter_length) * r->n_channels,
+ r->filter_length * 2 * r->n_channels);
+}
+
+static signed short
+double_to_s16 (double x)
+{
+ if (x < -32768) {
+ return -32768;
+ }
+ if (x > 32767) {
+ return -32767;
+ }
+ return rint (x);
+}
+
+/* only works for channels == 2 ???? */
+static void
+resample_sinc (ResampleState * r)
+{
+ double *ptr;
+ signed short *o_ptr;
+ int i, j;
+ double c0, c1;
+ double a;
+ int start;
+ double center;
+ double weight;
+ double x0, x, d;
+ double scale;
+
+ ptr = (double *) r->buffer;
+ o_ptr = (signed short *) r->o_buf;
+
+ /* scale provides a cutoff frequency for the low
+ * pass filter aspects of sinc(). scale=M_PI
+ * will cut off at the input frequency, which is
+ * good for up-sampling, but will cause aliasing
+ * for downsampling. Downsampling needs to be
+ * cut off at o_rate, thus scale=M_PI*r->i_inc. */
+ /* actually, it needs to be M_PI*r->i_inc*r->i_inc.
+ * Need to research why. */
+ scale = M_PI * r->i_inc;
+ for (i = 0; i < r->o_samples; i++) {
+ a = r->o_start + i * r->o_inc;
+ start = floor (a - r->halftaps);
+ center = a;
+ /*x = M_PI * (start - center) * r->o_inc; */
+ /*d = M_PI * r->o_inc; */
+ /*x = (start - center) * r->o_inc; */
+ x0 = (start - center) * r->o_inc;
+ d = r->o_inc;
+ c0 = 0;
+ c1 = 0;
+ for (j = 0; j < r->filter_length; j++) {
+ x = x0 + d * j;
+ weight = sinc (x * scale * r->i_inc) * scale / M_PI;
+ weight *= window_func (x / r->halftaps * r->i_inc);
+ c0 += weight * ptr[(start + j + r->filter_length) * 2 + 0];
+ c1 += weight * ptr[(start + j + r->filter_length) * 2 + 1];
+ }
+ o_ptr[0] = double_to_s16 (c0);
+ o_ptr[1] = double_to_s16 (c1);
+ o_ptr += 2;
+ }
+}
+#endif
+
+/*
+ * Resampling audio is best done using a sinc() filter.
+ *
+ *
+ * out[t] = Sum( in[t'] * sinc((t-t')/delta_t), all t')
+ *
+ * The immediate problem with this algorithm is that it involves a
+ * sum over an infinite number of input samples, both in the past
+ * and future. Note that even though sinc(x) is bounded by 1/x,
+ * and thus decays to 0 for large x, since sum(x,{x=0,1..,n}) diverges
+ * as log(n), we need to be careful about convergence. This is
+ * typically done by using a windowing function, which also makes
+ * the sum over a finite number of input samples.
+ *
+ * The next problem is computational: sinc(), and especially
+ * sinc() multiplied by a non-trivial windowing function is expensive
+ * to calculate, and also difficult to find SIMD optimizations. Since
+ * the time increment on input and output is different, it is not
+ * possible to use a FIR filter, because the taps would have to be
+ * recalculated for every t.
+ *
+ * To get around the expense of calculating sinc() for every point,
+ * we pre-calculate sinc() at a number of points, and then interpolate
+ * for the values we want in calculations. The interpolation method
+ * chosen is bi-cubic, which requires both the evalated function and
+ * its derivative at every pre-sampled point. Also, if the sampled
+ * points are spaced commensurate with the input delta_t, we notice
+ * that the interpolating weights are the same for every input point.
+ * This decreases the number of operations to 4 multiplies and 4 adds
+ * for each tap, regardless of the complexity of the filtering function.
+ *
+ * At this point, it is possible to rearrange the problem as the sum
+ * of 4 properly weghted FIR filters. Typical SIMD computation units
+ * are highly optimized for FIR filters, making long filter lengths
+ * reasonable.
+ */
+
+static void
+resample_sinc_ft (ResampleState * r)
+{
+ double *ptr;
+ signed short *o_ptr;
+ int i;
+
+ /*int j; */
+ double c0, c1;
+
+ /*double a; */
+ double start_f, start_x;
+ int start;
+ double center;
+
+ /*double weight; */
+ double x, d;
+ double scale;
+ int n = 4;
+
+ scale = r->i_inc; /* cutoff at 22050 */
+ /*scale = 1.0; // cutoff at 24000 */
+ /*scale = r->i_inc * 0.5; // cutoff at 11025 */
+
+ if (!r->ft) {
+ r->ft = functable_new ();
+
+ r->ft->len = (r->filter_length + 2) * n;
+ r->ft->offset = 1.0 / n;
+ r->ft->start = -r->ft->len * 0.5 * r->ft->offset;
+
+ r->ft->func_x = functable_sinc;
+ r->ft->func_dx = functable_dsinc;
+ r->ft->scale = M_PI * scale;
+
+ r->ft->func2_x = functable_window_std;
+ r->ft->func2_dx = functable_window_dstd;
+ r->ft->scale2 = 1.0 / r->halftaps;
+
+ functable_setup (r->ft);
+ }
+
+ ptr = r->buffer;
+ o_ptr = (signed short *) r->o_buf;
+
+ center = r->o_start;
+ start_x = center - r->halftaps;
+ start_f = floor (start_x);
+ start_x -= start_f;
+ start = start_f;
+ for (i = 0; i < r->o_samples; i++) {
+ /*start_f = floor(center - r->halftaps); */
+ x = start_f - center;
+ d = 1;
+ c0 = 0;
+ c1 = 0;
+/*#define slow */
+#ifdef slow
+ for (j = 0; j < r->filter_length; j++) {
+ weight = functable_eval (r->ft, x) * scale;
+ /*weight = sinc(M_PI * scale * x)*scale*r->i_inc; */
+ /*weight *= window_func(x / r->halftaps); */
+ c0 += weight * ptr[(start + j + r->filter_length) * 2 + 0];
+ c1 += weight * ptr[(start + j + r->filter_length) * 2 + 1];
+ x += d;
+ }
+#else
+ functable_fir2 (r->ft,
+ &c0, &c1, x, n, ptr + (start + r->filter_length) * 2, r->filter_length);
+ c0 *= scale;
+ c1 *= scale;
+#endif
+
+ r->out_tmp[2 * i + 0] = c0;
+ r->out_tmp[2 * i + 1] = c1;
+ center += r->o_inc;
+ start_x += r->o_inc;
+ while (start_x >= 1.0) {
+ start_f++;
+ start_x -= 1.0;
+ start++;
+ }
+ }
+
+}
+
diff --git a/examples/audioresample/resample.c b/examples/audioresample/resample.c
new file mode 100644
index 0000000..9d9abb3
--- /dev/null
+++ b/examples/audioresample/resample.c
@@ -0,0 +1,226 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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;
+
+ OIL_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/examples/audioresample/resample.h b/examples/audioresample/resample.h
new file mode 100644
index 0000000..96f8ff0
--- /dev/null
+++ b/examples/audioresample/resample.h
@@ -0,0 +1,121 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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/examples/audioresample/resample_chunk.c b/examples/audioresample/resample_chunk.c
new file mode 100644
index 0000000..50c5924
--- /dev/null
+++ b/examples/audioresample/resample_chunk.c
@@ -0,0 +1,200 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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);
+ OIL_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;
+ OIL_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;
+
+ OIL_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) {
+ OIL_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) {
+ OIL_ERROR("buffer_queue_pull returned NULL");
+ return;
+ }
+
+ r->i_start += r->i_inc;
+ OIL_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/examples/audioresample/resample_functable.c b/examples/audioresample/resample_functable.c
new file mode 100644
index 0000000..5bff7b0
--- /dev/null
+++ b/examples/audioresample/resample_functable.c
@@ -0,0 +1,271 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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);
+ OIL_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;
+ OIL_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;
+
+ OIL_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) {
+ OIL_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) {
+ OIL_ERROR("buffer_queue_pull returned NULL");
+ return;
+ }
+
+ r->i_start += r->i_inc;
+ OIL_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/examples/audioresample/resample_ref.c b/examples/audioresample/resample_ref.c
new file mode 100644
index 0000000..163748c
--- /dev/null
+++ b/examples/audioresample/resample_ref.c
@@ -0,0 +1,200 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#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);
+ OIL_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;
+ OIL_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;
+
+ OIL_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) {
+ OIL_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) {
+ OIL_ERROR("buffer_queue_pull returned NULL");
+ return;
+ }
+
+ r->i_start += r->i_inc;
+ OIL_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/examples/audioresample/test_functable1.c b/examples/audioresample/test_functable1.c
new file mode 100644
index 0000000..dfc57e5
--- /dev/null
+++ b/examples/audioresample/test_functable1.c
@@ -0,0 +1,289 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2001,2006 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <liboil/liboildebug.h>
+
+#include "functable.h"
+
+
+
+#if 0
+void
+functable_function_sinc(double *fx, double *dfx, double x,
+ double param1, double param2)
+{
+ if(x==0){
+ *fx = 1;
+ *dfx = 0;
+ return;
+ }
+
+ *fx = sin(x)/x;
+ *dfx = (cos(x) - sin(x)/x)/x;
+}
+
+void
+functable_function_boxcar(double *fx, double *dfx, double x,
+ double param1, double param2)
+{
+ double width = param1;
+
+ if (x < width && x > -width) {
+ *fx = 1;
+ } else {
+ *fx = 0;
+ }
+ *dfx = 0;
+}
+
+void
+functable_function_hanning(double *fx, double *dfx, double x,
+ double param1, double param2)
+{
+ double width = param1;
+
+ 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 (int length, int oversample, double offset, double multiplier)
+{
+ Functable *ft;
+
+ ft = malloc (sizeof(Functable));
+ memset (ft, 0, sizeof(Functable));
+
+ ft->length = length;
+ ft->offset = offset;
+ ft->multiplier = multiplier;
+ ft->oversample = oversample;
+
+ ft->inv_multiplier = 1.0 / ft->multiplier;
+ ft->submultiplier = ft->multiplier / ft->oversample;
+ ft->inv_submultiplier = 1.0 / ft->inv_submultiplier;
+
+ ft->fx = malloc(sizeof(double)*ft->length*(ft->oversample + 1));
+ ft->dfx = malloc(sizeof(double)*ft->length*(ft->oversample + 1));
+
+ memset (ft->fx, 0, sizeof(double)*ft->length*(ft->oversample + 1));
+ memset (ft->dfx, 0, sizeof(double)*ft->length*(ft->oversample + 1));
+
+ return ft;
+}
+
+void
+functable_free (Functable *ft)
+{
+ free (ft->fx);
+ free (ft->dfx);
+ free (ft);
+}
+
+void
+functable_calculate (Functable *t, FunctableFunc func, double param1,
+ double param2)
+{
+ int i, j;
+ double x;
+ double *fx;
+ double *dfx;
+
+ for(j=0;j<t->oversample + 1;j++){
+ fx = t->fx + t->length*j;
+ dfx = t->dfx + t->length*j;
+ for(i=0;i<t->length;i++){
+ x = t->offset + t->submultiplier * (i * t->oversample + j);
+
+ func (&fx[i], &dfx[i], x, param1, param2);
+ dfx[i] *= t->submultiplier;
+ }
+ }
+}
+
+void
+functable_calculate_multiply (Functable *t, FunctableFunc func,
+ double param1, double param2)
+{
+ int i;
+ int j;
+ double x;
+ double *fx;
+ double *dfx;
+ double afx, dafx, bfx, dbfx;
+
+ for(j=0;j<t->oversample + 1;j++){
+ fx = t->fx + t->length*j;
+ dfx = t->dfx + t->length*j;
+ for(i=0;i<t->length;i++){
+ x = t->offset + t->submultiplier * (i * t->oversample + j);
+
+ afx = fx[i];
+ dafx = dfx[i];
+ func (&bfx, &dbfx, x, param1, param2);
+ fx[i] = afx * bfx;
+ dfx[i] = afx * dbfx + dafx * bfx;
+ }
+ }
+}
+
+double
+functable_evaluate (Functable *t, double x)
+{
+ int i, j;
+ double f0, f1, w0, w1;
+ double x2, x3;
+ double w;
+ double *fx1, *fx2;
+ double *dfx1, *dfx2;
+ int xi;
+
+ if(x<t->offset || x>(t->offset+t->length*t->multiplier)){
+ OIL_DEBUG ("x out of range %g",x);
+ return 0;
+ }
+
+ x -= t->offset;
+ x *= t->inv_submultiplier;
+ xi = floor(x);
+ j = xi % t->oversample;
+ i = xi / t->oversample;
+ x -= xi;
+
+ fx1 = t->fx + j*t->length;
+ fx2 = t->fx + (j+1)*t->length;
+ dfx1 = t->dfx + j*t->length;
+ dfx2 = t->dfx + (j+1)*t->length;
+
+ x2 = x * x;
+ x3 = x2 * x;
+
+ f1 = 3 * x2 - 2 * x3;
+ f0 = 1 - f1;
+ w0 = x - 2 * x2 + x3;
+ w1 = -x2 + x3;
+
+ w = fx1[i] * f0 + fx2[i] * f1 + dfx1[i] * w0 + dfx2[i] * w1;
+
+ return w;
+}
+
+double
+functable_mult_and_sum (Functable *t, double x, double *data, int n)
+{
+ int i, j;
+ double f0, f1, w0, w1;
+ double x2, x3;
+ double w;
+ double *fx1, *fx2;
+ double *dfx1, *dfx2;
+ int xi;
+ double sum;
+
+ if(x<t->offset || x>(t->offset+t->length*t->multiplier)){
+ OIL_DEBUG ("x out of range %g",x);
+ return 0;
+ }
+
+ x -= t->offset;
+ x *= t->inv_submultiplier;
+ xi = floor(x);
+ j = xi % t->oversample;
+ i = xi / t->oversample;
+ x -= xi;
+
+ fx1 = t->fx + j*t->length + i;
+ fx2 = t->fx + (j+1)*t->length + i;
+ dfx1 = t->dfx + j*t->length + i;
+ dfx2 = t->dfx + (j+1)*t->length + i;
+
+ x2 = x * x;
+ x3 = x2 * x;
+
+ f1 = 3 * x2 - 2 * x3;
+ f0 = 1 - f1;
+ w0 = x - 2 * x2 + x3;
+ w1 = -x2 + x3;
+
+ sum = 0;
+ for(i=0;i<n;i++){
+ w = fx1[i] * f0 + fx2[i] * f1 + dfx1[i] * w0 + dfx2[i] * w1;
+ sum += w * data[i];
+ }
+
+ return sum;
+}
+
+
+#endif
+
+void dump_functable(Functable *ft);
+
+int
+main (int argc, char *argv[])
+{
+ Functable *ft;
+
+ ft = functable_new (10, 1, -10.0, 2.0);
+
+ functable_calculate (ft, functable_function_sinc, 10, 0);
+
+ dump_functable(ft);
+
+ functable_free(ft);
+
+ return 0;
+}
+
+void
+dump_functable(Functable *ft)
+{
+ int i;
+ double x;
+
+ for(i=0;i<2000;i++){
+ x = -10.0 + 0.01*i;
+ printf("%g %g\n", x, functable_evaluate (ft, x));
+ }
+}
+