gst/audioscale/: remove

Original commit message from CVS:

* gst/audioscale/.cvsignore:
* gst/audioscale/Makefile.am:
* gst/audioscale/README:
* gst/audioscale/audioscale.vcproj:
* gst/audioscale/dtof.c:
* gst/audioscale/dtos.c:
* gst/audioscale/functable.c:
* gst/audioscale/gstaudioscale.c:
* gst/audioscale/gstaudioscale.h:
* gst/audioscale/private.h:
* gst/audioscale/resample.c:
* gst/audioscale/resample.h:
* gst/audioscale/test.c:
remove
This commit is contained in:
Thomas Vander Stichele 2005-11-30 01:04:28 +00:00
parent 573b0b8166
commit 8be52e0b73
14 changed files with 17 additions and 3193 deletions

View file

@ -1,3 +1,20 @@
2005-11-30 Thomas Vander Stichele <thomas at apestaart dot org>
* gst/audioscale/.cvsignore:
* gst/audioscale/Makefile.am:
* gst/audioscale/README:
* gst/audioscale/audioscale.vcproj:
* gst/audioscale/dtof.c:
* gst/audioscale/dtos.c:
* gst/audioscale/functable.c:
* gst/audioscale/gstaudioscale.c:
* gst/audioscale/gstaudioscale.h:
* gst/audioscale/private.h:
* gst/audioscale/resample.c:
* gst/audioscale/resample.h:
* gst/audioscale/test.c:
remove
2005-11-30 Edward Hervey <edward@fluendo.com>
* gst-libs/gst/netbuffer/Makefile.am:

View file

@ -1,7 +0,0 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

View file

@ -1,14 +0,0 @@
#plugin_LTLIBRARIES = libgstaudioscale.la
noinst_LTLIBRARIES = libgstresample.la
#libgstaudioscale_la_SOURCES = gstaudioscale.c
#libgstaudioscale_la_CFLAGS = $(GST_CFLAGS)
#libgstaudioscale_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
#libgstaudioscale_la_LIBADD = $(GST_LIBS)
noinst_HEADERS = gstaudioscale.h private.h
libgstresample_la_SOURCES = dtos.c dtof.c functable.c resample.c resample.h
libgstresample_la_LIBADD = $(GST_LIBS)
libgstresample_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstresample_la_CFLAGS = $(GST_CFLAGS)

View file

@ -1,62 +0,0 @@
This is a snapshot of my current work developing an audio
resampling library. While working on this library, I started
writing lots of general purpose functions that should really
be part of a larger library. Rather than have a constantly
changing library, and since the current code is capable, I
decided to freeze this codebase for use with gstreamer, and
move active development of the code elsewhere.
The algorithm used is based on Shannon's theorem, which says
that you can recreate an input signal from equidistant samples
using a sin(x)/x filter; thus, you can create new samples from
the regenerated input signal. Since sin(x)/x is expensive to
evaluate, an interpolated lookup table is used. Also, a
windowing function (1-x^2)^2 is used, which aids the convergence
of sin(x)/x for lower frequencies at the expense of higher.
There is one tunable parameter, which is the filter length.
Longer filter lengths are obviously slower, but more accurate.
There's not much reason to use a filter length longer than 64,
since other approximations start to dominate. Filter lengths
as short as 8 are audially acceptable, but should not be
considered for serious work.
Performance: A PowerPC G4 at 400 Mhz can resample 2 audio
channels at almost 10x speed with a filter length of 64, without
using Altivec extensions. (My goal was 10x speed, which I almost
reached. Maybe later.)
Limitations: Currently only supports streams in the form of
interleaved signed 16-bit samples.
The test.c program is a simple regression test. It creates a
test input pattern (1 sec at 48 khz) that is a frequency ramp
from 0 to 24000 hz, and then converts it to 44100 hz using a
filter length of 64. It then compares the result to the same
pattern generated at 44100 hz, and outputs the result to the
file "out".
A graph of the correct output should have field 2 and field 4
almost equal (plus/minus 1) up to about sample 40000 (which
corresponds to 20 khz), and then field 2 should be close to 0
above that. Running the test program will print to stdout
something like the following:
time 0.112526
average error 10k=0.4105 22k=639.34
The average error is RMS error over the range [0-10khz] and
[0-22khz], and is expressed in sample values, for an input
amplitude of 16000. Note that RMS errors below 1.0 can't
really be compared, but basically this shows that below
10 khz, the resampler is nearly perfect. Most of the error
is concentrated above 20 khz.
If the average error is significantly larger after modifying
the code, it's probably not good.
dave...

View file

@ -1,148 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="audioscale"
ProjectGUID="{979C216F-0ACF-4956-AE00-055A42D678A7}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../../win32/Debug"
IntermediateDirectory="../../win32/Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;audioscale_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
OutputFile="$(OutDir)/gstaudioscale.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="../../../gstreamer/win32/Debug;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
ModuleDefinitionFile=""
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/audioscale.pdb"
SubSystem="2"
OptimizeReferences="2"
ImportLibrary="$(OutDir)/gstaudioscale.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../../win32/Release"
IntermediateDirectory="../../win32/Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
PreprocessorDefinitions="WIN32;NDEBUG;GST_DISABLE_GST_DEBUG;_WINDOWS;_USRDLL;audioscale_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
OutputFile="$(OutDir)/gstaudioscale.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../gstreamer/win32/Release;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
ModuleDefinitionFile=""
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/gstaudioscale.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\gstaudioscale.c">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\gstaudioscale.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -1,74 +0,0 @@
/* 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 <ml.h> */
#include "private.h"
void
conv_double_float_ref (double *dest, float *src, int n)
{
int i;
for (i = 0; i < n; i++) {
dest[i] = src[i];
}
}
void
conv_float_double_ref (float *dest, double *src, int n)
{
int i;
for (i = 0; i < n; i++) {
dest[i] = src[i];
}
}
void
conv_double_float_dstr (double *dest, float *src, int n, int dstr)
{
int i;
void *d = dest;
for (i = 0; i < n; i++) {
(*(double *) d) = *src++;
d += dstr;
}
}
void
conv_float_double_sstr (float *dest, double *src, int n, int sstr)
{
int i;
void *s = src;
for (i = 0; i < n; i++) {
*dest++ = *(double *) s;
s += sstr;
}
}

View file

@ -1,217 +0,0 @@
/* 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 <ml.h> */
#include <resample.h>
#define short_to_double_table
/*#define short_to_double_altivec */
#define short_to_double_unroll
#ifdef short_to_double_table
static float ints_high[256];
static float ints_low[256];
void
conv_double_short_table (double *dest, short *src, int n)
{
static int init = 0;
int i;
unsigned int idx;
if (!init) {
for (i = 0; i < 256; i++) {
ints_high[i] = 256.0 * ((i < 128) ? i : i - 256);
ints_low[i] = i;
}
init = 1;
}
if (n & 1) {
idx = (unsigned short) *src++;
*dest++ = ints_high[(idx >> 8)] + ints_low[(idx & 0xff)];
n -= 1;
}
for (i = 0; i < n; i += 2) {
idx = (unsigned short) *src++;
*dest++ = ints_high[(idx >> 8)] + ints_low[(idx & 0xff)];
idx = (unsigned short) *src++;
*dest++ = ints_high[(idx >> 8)] + ints_low[(idx & 0xff)];
}
}
#endif
#ifdef short_to_double_unroll
void
conv_double_short_unroll (double *dest, short *src, int n)
{
if (n & 1) {
*dest++ = *src++;
n--;
}
if (n & 2) {
*dest++ = *src++;
*dest++ = *src++;
n -= 2;
}
while (n > 0) {
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
n -= 4;
}
}
#endif
void
conv_double_short_ref (double *dest, short *src, int n)
{
int i;
for (i = 0; i < n; i++) {
dest[i] = src[i];
}
}
#ifdef HAVE_CPU_PPC
#if 0
static union
{
int i[4];
float f[4];
}
av_tmp __attribute__ ((__aligned__ (16)));
void
conv_double_short_altivec (double *dest, short *src, int n)
{
int i;
for (i = 0; i < n; i += 4) {
av_tmp.i[0] = src[0];
av_tmp.i[1] = src[1];
av_tmp.i[2] = src[2];
av_tmp.i[3] = src[3];
asm (" lvx 0,0,%0\n" " vcfsx 1,0,0\n" " stvx 1,0,%0\n": :"r" (&av_tmp)
);
dest[0] = av_tmp.f[0];
dest[1] = av_tmp.f[1];
dest[2] = av_tmp.f[2];
dest[3] = av_tmp.f[3];
src += 4;
dest += 4;
}
}
#endif
#endif
/* double to short */
void
conv_short_double_ref (short *dest, double *src, int n)
{
int i;
double x;
for (i = 0; i < n; i++) {
x = *src++;
if (x < -32768.0)
x = -32768.0;
if (x > 32767.0)
x = 32767.0;
*dest++ = rint (x);
}
}
/* #ifdef HAVE_CPU_PPC */
#if 0
void
conv_short_double_ppcasm (short *dest, double *src, int n)
{
int tmp[2];
double min = -32768.0;
double max = 32767.0;
double ftmp0, ftmp1;
asm __volatile__ ("\taddic. %3,%3,-8\n"
"\taddic. %6,%6,-2\n"
"loop:\n"
"\tlfdu %0,8(%3)\n"
"\tfsub %1,%0,%4\n"
"\tfsel %0,%1,%0,%4\n"
"\tfsub %1,%0,%5\n"
"\tfsel %0,%1,%5,%0\n"
"\tfctiw %1,%0\n"
"\taddic. 5,5,-1\n"
"\tstfd %1,0(%2)\n"
"\tlhz 9,6(%2)\n"
"\tsthu 9,2(%6)\n" "\tbne loop\n":"=&f" (ftmp0), "=&f" (ftmp1)
:"b" (tmp), "r" (src), "f" (min), "f" (max), "r" (dest)
:"r9", "r5");
}
#endif
void
conv_double_short_dstr (double *dest, short *src, int n, int dstr)
{
int i;
void *d = dest;
for (i = 0; i < n; i++) {
(*(double *) d) = *src++;
d += dstr;
}
}
void
conv_short_double_sstr (short *dest, double *src, int n, int sstr)
{
int i;
double x;
void *s = src;
for (i = 0; i < n; i++) {
x = *(double *) s;
if (x < -32768.0)
x = -32768.0;
if (x > 32767.0)
x = 32767.0;
*dest++ = rint (x);
s += sstr;
}
}

View file

@ -1,322 +0,0 @@
/* 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 "private.h"
double
functable_sinc (void *p, double x)
{
if (x == 0)
return 1;
return sin (x) / x;
}
double
functable_dsinc (void *p, double x)
{
if (x == 0)
return 0;
return cos (x) / x - sin (x) / (x * x);
}
double
functable_window_boxcar (void *p, double x)
{
if (x < -1 || x > 1)
return 0;
return 1;
}
double
functable_window_dboxcar (void *p, double x)
{
return 0;
}
double
functable_window_std (void *p, double x)
{
if (x < -1 || x > 1)
return 0;
return (1 - x * x) * (1 - x * x);
}
double
functable_window_dstd (void *p, double x)
{
if (x < -1 || x > 1)
return 0;
return -4 * x * (1 - x * x);
}
void
functable_init (functable_t * t)
{
int i;
double x;
t->fx = malloc (sizeof (double) * (t->len + 1));
t->fdx = malloc (sizeof (double) * (t->len + 1));
t->invoffset = 1.0 / t->offset;
for (i = 0; i < t->len + 1; i++) {
x = t->start + t->offset * i;
x *= t->scale;
t->fx[i] = t->func_x (t->priv, x);
t->fdx[i] = t->scale * t->func_dx (t->priv, x);
}
if (t->func2_x) {
double f1x, f1dx;
double f2x, f2dx;
for (i = 0; i < t->len + 1; i++) {
x = t->start + t->offset * i;
x *= t->scale2;
f2x = t->func2_x (t->priv, x);
f2dx = t->scale2 * t->func2_dx (t->priv, x);
f1x = t->fx[i];
f1dx = t->fdx[i];
t->fx[i] = f1x * f2x;
t->fdx[i] = f1x * f2dx + f1dx * f2x;
}
}
}
double
functable_eval (functable_t * t, double x)
{
int i;
double f0, f1, w0, w1;
double x2, x3;
double w;
if (x < t->start || x > (t->start + (t->len + 1) * t->offset)) {
printf ("x out of range %g\n", x);
}
x -= t->start;
x /= t->offset;
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->offset;
w1 = (-x2 + x3) * t->offset;
/*printf("i=%d x=%g f0=%g f1=%g w0=%g w1=%g\n",i,x,f0,f1,w0,w1); */
w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->fdx[i] * w0 + t->fdx[i + 1] * w1;
/*w = t->fx[i] * (1-x) + t->fx[i+1] * x; */
return w;
}
double
functable_fir (functable_t * 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->start;
x /= t->offset;
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->offset;
w1 = (-x2 + x3) * t->offset;
sum = 0;
for (j = 0; j < len; j++) {
w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->fdx[i] * w0 + t->fdx[i + 1] * w1;
sum += data[j * 2] * w;
i += n;
}
return sum;
}
void
functable_fir2 (functable_t * 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->start;
x *= t->invoffset;
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->offset;
w1 = (-x2 + x3) * t->offset;
sum0 = 0;
sum1 = 0;
for (j = 0; j < len; j++) {
w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->fdx[i] * w0 + t->fdx[i + 1] * w1;
sum0 += data[j * 2] * w;
sum1 += data[j * 2 + 1] * w;
i += n;
#define unroll2
#define unroll3
#define unroll4
#ifdef unroll2
j++;
w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->fdx[i] * w0 + t->fdx[i + 1] * w1;
sum0 += data[j * 2] * w;
sum1 += data[j * 2 + 1] * w;
i += n;
#endif
#ifdef unroll3
j++;
w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->fdx[i] * w0 + t->fdx[i + 1] * w1;
sum0 += data[j * 2] * w;
sum1 += data[j * 2 + 1] * w;
i += n;
#endif
#ifdef unroll4
j++;
w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->fdx[i] * w0 + t->fdx[i + 1] * w1;
sum0 += data[j * 2] * w;
sum1 += data[j * 2 + 1] * w;
i += n;
#endif
}
*r0 = sum0;
*r1 = sum1;
}
#ifdef unused
void
functable_fir2_altivec (functable_t * t, float *r0, float *r1,
double x, int n, float *data, int len)
{
int i, j;
double f0, f1, w0, w1;
double x2, x3;
double w;
double sum0, sum1;
double floor_x;
x -= t->start;
x *= t->invoffset;
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->offset;
w1 = (-x2 + x3) * t->offset;
sum0 = 0;
sum1 = 0;
for (j = 0; j < len; j++) {
/* t->fx, t->fdx needs to be multiplexed by n */
/* we need 5 consecutive floats, which fit into 2 vecs */
/* load v0, t->fx[i] */
/* load v1, t->fx[i+n] */
/* v2 = v0 (not correct) */
/* v3 = (v0>>32) || (v1<<3*32) (not correct) */
/* */
/* load v4, t->dfx[i] */
/* load v5, t->dfx[i+n] */
/* v6 = v4 (not correct) */
/* v7 = (v4>>32) || (v5<<3*32) (not correct) */
/* */
/* v8 = splat(f0) */
/* v9 = splat(f1) */
/* v10 = splat(w0) */
/* v11 = splat(w1) */
/* */
/* v12 = v2 * v8 */
/* v12 += v3 * v9 */
/* v12 += v6 * v10 */
/* v12 += v7 * v11 */
w = t->fx[i] * f0 + t->fx[i + 1] * f1 + t->fdx[i] * w0 + t->fdx[i + 1] * w1;
/* v13 = data[j*2] */
/* v14 = data[j*2+4] */
/* v15 = deinterlace_high(v13,v14) */
/* v16 = deinterlace_low(v13,v14) */
/* (sum0) v17 += multsum(v13,v15) */
/* (sum1) v18 += multsum(v14,v16) */
sum0 += data[j * 2] * w;
sum1 += data[j * 2 + 1] * w;
i += n;
}
*r0 = sum0;
*r1 = sum1;
}
#endif

View file

@ -1,735 +0,0 @@
/* 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.
*/
/* Element-Checklist-Version: 5 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <math.h>
/*#define DEBUG_ENABLED */
#include "gstaudioscale.h"
#include <gst/audio/audio.h>
#include <gst/resample/resample.h>
GST_DEBUG_CATEGORY_STATIC (audioscale_debug);
#define GST_CAT_DEFAULT audioscale_debug
/* elementfactory information */
static GstElementDetails gst_audioscale_details =
GST_ELEMENT_DETAILS ("Audio scaler",
"Filter/Converter/Audio",
"Resample audio",
"David Schleef <ds@schleef.org>");
/* Audioscale signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_FILTERLEN,
ARG_METHOD
/* FILL ME */
};
#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 */
#define NOTHING "audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ], " \
"endianness = (int) BYTE_ORDER, " "width = (int) 32")
#endif
static GstStaticPadTemplate gst_audioscale_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_ALWAYS, SUPPORTED_CAPS);
static GstStaticPadTemplate gst_audioscale_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_ALWAYS, SUPPORTED_CAPS);
#define GST_TYPE_AUDIOSCALE_METHOD (gst_audioscale_method_get_type())
static GType
gst_audioscale_method_get_type (void)
{
static GType audioscale_method_type = 0;
static GEnumValue audioscale_methods[] = {
{GST_RESAMPLE_NEAREST, "Nearest", "nearest"},
{GST_RESAMPLE_BILINEAR, "Bilinear", "bilinear"},
{GST_RESAMPLE_SINC, "Sinc", "sinc"},
{0, NULL, NULL},
};
if (!audioscale_method_type) {
audioscale_method_type = g_enum_register_static ("GstAudioscaleMethod",
audioscale_methods);
}
return audioscale_method_type;
}
static void gst_audioscale_base_init (gpointer g_class);
static void gst_audioscale_class_init (AudioscaleClass * klass);
static void gst_audioscale_init (Audioscale * audioscale);
static void gst_audioscale_dispose (GObject * object);
static void gst_audioscale_chain (GstPad * pad, GstData * _data);
static GstStateChangeReturn gst_audioscale_change_state (GstElement * element,
GstStateChange transition);
static void gst_audioscale_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_audioscale_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void *gst_audioscale_get_buffer (void *priv, unsigned int size);
static GstElementClass *parent_class = NULL;
/*static guint gst_audioscale_signals[LAST_SIGNAL] = { 0 }; */
GType
audioscale_get_type (void)
{
static GType audioscale_type = 0;
if (!audioscale_type) {
static const GTypeInfo audioscale_info = {
sizeof (AudioscaleClass),
gst_audioscale_base_init,
NULL,
(GClassInitFunc) gst_audioscale_class_init,
NULL,
NULL,
sizeof (Audioscale), 0, (GInstanceInitFunc) gst_audioscale_init,
};
audioscale_type =
g_type_register_static (GST_TYPE_ELEMENT, "Audioscale",
&audioscale_info, 0);
}
return audioscale_type;
}
static void
gst_audioscale_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_audioscale_src_template));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_audioscale_sink_template));
gst_element_class_set_details (gstelement_class, &gst_audioscale_details);
}
static void
gst_audioscale_class_init (AudioscaleClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = gst_audioscale_set_property;
gobject_class->get_property = gst_audioscale_get_property;
gobject_class->dispose = gst_audioscale_dispose;
gstelement_class->change_state = gst_audioscale_change_state;
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));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD,
g_param_spec_enum ("method", "method", "method",
GST_TYPE_AUDIOSCALE_METHOD, GST_RESAMPLE_SINC,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
GST_DEBUG_CATEGORY_INIT (audioscale_debug, "audioscale", 0,
"audioscale element");
}
static GstStaticCaps gst_audioscale_passthru_caps =
GST_STATIC_CAPS ("audio/x-raw-int, channels = [ 3, MAX ]");
static GstStaticCaps gst_audioscale_convert_caps =
GST_STATIC_CAPS ("audio/x-raw-int, channels = [ 1, 2 ]");
static GstCaps *
gst_audioscale_expand_caps (const GstCaps * caps)
{
GstCaps *caps1, *caps2;
int i;
caps1 = gst_caps_intersect (caps,
gst_static_caps_get (&gst_audioscale_passthru_caps));
caps2 = gst_caps_intersect (caps,
gst_static_caps_get (&gst_audioscale_convert_caps));
for (i = 0; i < gst_caps_get_size (caps2); i++) {
GstStructure *structure = gst_caps_get_structure (caps2, i);
gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
NULL);
}
gst_caps_append (caps1, caps2);
return caps1;
}
static GstCaps *
gst_audioscale_getcaps (GstPad * pad)
{
Audioscale *audioscale;
GstPad *otherpad;
GstCaps *othercaps;
GstCaps *caps;
audioscale = GST_AUDIOSCALE (gst_pad_get_parent (pad));
otherpad = (pad == audioscale->srcpad) ? audioscale->sinkpad :
audioscale->srcpad;
othercaps = gst_pad_get_allowed_caps (otherpad);
caps = gst_audioscale_expand_caps (othercaps);
gst_caps_free (othercaps);
return caps;
}
static GstCaps *
gst_audioscale_fixate (GstPad * pad, const GstCaps * caps)
{
Audioscale *audioscale;
gst_resample_t *r;
GstPad *otherpad;
int rate;
GstCaps *copy;
GstStructure *structure;
audioscale = GST_AUDIOSCALE (gst_pad_get_parent (pad));
r = &(audioscale->gst_resample_template);
if (pad == audioscale->srcpad) {
otherpad = audioscale->sinkpad;
rate = r->i_rate;
} else {
otherpad = audioscale->srcpad;
rate = r->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 (gst_structure_fixate_field_nearest_int (structure, "rate", rate))
return copy;
gst_caps_free (copy);
return NULL;
}
static GstPadLinkReturn
gst_audioscale_link (GstPad * pad, const GstCaps * caps)
{
Audioscale *audioscale;
gst_resample_t *r;
GstStructure *structure;
double *rate, *otherrate;
double temprate;
int temp;
gboolean ret;
GstPadLinkReturn link_ret;
GstPad *otherpad;
GstCaps *copy;
audioscale = GST_AUDIOSCALE (gst_pad_get_parent (pad));
r = &(audioscale->gst_resample_template);
if (pad == audioscale->srcpad) {
otherpad = audioscale->sinkpad;
rate = &r->o_rate;
otherrate = &r->i_rate;
} else {
otherpad = audioscale->srcpad;
rate = &r->i_rate;
otherrate = &r->o_rate;
}
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "rate", &temp);
ret &= gst_structure_get_int (structure, "channels", &r->channels);
g_return_val_if_fail (ret, GST_PAD_LINK_REFUSED);
*rate = (double) temp;
copy = gst_audioscale_expand_caps (caps);
link_ret = gst_pad_try_set_caps_nonfixed (otherpad, copy);
gst_caps_free (copy);
if (GST_PAD_LINK_FAILED (link_ret))
return link_ret;
caps = gst_pad_get_negotiated_caps (otherpad);
g_return_val_if_fail (caps, GST_PAD_LINK_REFUSED);
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "rate", &temp);
g_return_val_if_fail (ret, GST_PAD_LINK_REFUSED);
*otherrate = (double) temp;
if (g_str_equal (gst_structure_get_name (structure), "audio/x-raw-float")) {
r->format = GST_RESAMPLE_FLOAT;
} else {
r->format = GST_RESAMPLE_S16;
}
audioscale->passthru = (r->i_rate == r->o_rate);
audioscale->increase = (r->o_rate >= r->i_rate);
/* now create audioscale iterations */
audioscale->num_iterations = 0;
temprate = r->i_rate;
while (TRUE) {
if (r->o_rate > r->i_rate) {
if (temprate >= r->o_rate)
break;
temprate *= 2;
} else {
if (temprate <= r->o_rate)
break;
temprate /= 2;
}
audioscale->num_iterations++;
}
if (audioscale->num_iterations > 0) {
audioscale->offsets = g_new0 (gint64, audioscale->num_iterations);
audioscale->gst_resample = g_new0 (gst_resample_t, 1);
audioscale->gst_resample->priv = audioscale;
audioscale->gst_resample->get_buffer = gst_audioscale_get_buffer;
audioscale->gst_resample->method = r->method;
audioscale->gst_resample->channels = r->channels;
audioscale->gst_resample->filter_length = r->filter_length;
audioscale->gst_resample->format = r->format;
if (audioscale->increase) {
temprate = r->o_rate;
while (temprate / 2 >= r->i_rate) {
temprate = temprate / 2;
}
/* now temprate is output rate of gstresample */
GST_DEBUG ("gstresample will increase rate from %f to %f", r->i_rate,
temprate);
audioscale->gst_resample->o_rate = temprate;
audioscale->gst_resample->i_rate = r->i_rate;
} else {
temprate = r->i_rate;
while (temprate / 2 >= r->o_rate) {
temprate = temprate / 2;
}
/* now temprate is input rate of gstresample */
GST_DEBUG ("gstresample will decrease rate from %f to %f", temprate,
r->o_rate);
audioscale->gst_resample->o_rate = r->o_rate;
audioscale->gst_resample->i_rate = temprate;
}
audioscale->passthru =
(audioscale->gst_resample->i_rate == audioscale->gst_resample->o_rate);
if (!audioscale->passthru)
audioscale->num_iterations--;
GST_DEBUG ("Number of iterations: %d", audioscale->num_iterations);
gst_resample_init (audioscale->gst_resample);
}
return link_ret;
}
static void *
gst_audioscale_get_buffer (void *priv, unsigned int size)
{
Audioscale *audioscale = priv;
GST_DEBUG ("size requested: %u irate: %f orate: %f", size,
audioscale->gst_resample->i_rate, audioscale->gst_resample->o_rate);
audioscale->outbuf = gst_buffer_new ();
GST_BUFFER_SIZE (audioscale->outbuf) = size;
GST_BUFFER_DATA (audioscale->outbuf) = g_malloc (size);
GST_BUFFER_TIMESTAMP (audioscale->outbuf) =
audioscale->gst_resample_offset * GST_SECOND /
audioscale->gst_resample->o_rate;
audioscale->gst_resample_offset +=
size / sizeof (gint16) / audioscale->gst_resample->channels;
return GST_BUFFER_DATA (audioscale->outbuf);
}
/* reduces rate by factor of 2 */
GstBuffer *
gst_audioscale_decrease_rate (Audioscale * audioscale,
GstBuffer * buf, double outrate, int cur_iteration)
{
gint i, j, curoffset;
GstBuffer *outbuf = gst_buffer_new ();
gint16 *outdata;
gint16 *indata;
GST_BUFFER_SIZE (outbuf) = GST_BUFFER_SIZE (buf) / 2;
outdata = g_malloc (GST_BUFFER_SIZE (outbuf));
indata = (gint16 *) GST_BUFFER_DATA (buf);
GST_DEBUG
("iteration = %d channels = %d in size = %d out size = %d outrate = %f",
cur_iteration, audioscale->gst_resample_template.channels,
GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (outbuf), outrate);
curoffset = 0;
for (i = 0; i < GST_BUFFER_SIZE (buf) / (sizeof (gint16));
i += 2 * audioscale->gst_resample_template.channels) {
for (j = 0; j < audioscale->gst_resample_template.channels; j++) {
outdata[curoffset + j] =
(indata[i + j] + indata[i + j +
audioscale->gst_resample_template.channels]) / 2;
}
curoffset += audioscale->gst_resample_template.channels;
}
GST_BUFFER_DATA (outbuf) = (gpointer) outdata;
GST_BUFFER_TIMESTAMP (outbuf) =
audioscale->offsets[cur_iteration] * GST_SECOND / outrate;
audioscale->offsets[cur_iteration] +=
GST_BUFFER_SIZE (outbuf) / sizeof (gint16) /
audioscale->gst_resample->channels;
return outbuf;
}
/* increases rate by factor of 2 */
GstBuffer *
gst_audioscale_increase_rate (Audioscale * audioscale,
GstBuffer * buf, double outrate, int cur_iteration)
{
gint i, j, curoffset;
GstBuffer *outbuf = gst_buffer_new ();
gint16 *outdata;
gint16 *indata;
GST_BUFFER_SIZE (outbuf) = GST_BUFFER_SIZE (buf) * 2;
outdata = g_malloc (GST_BUFFER_SIZE (outbuf));
indata = (gint16 *) GST_BUFFER_DATA (buf);
GST_DEBUG
("iteration = %d channels = %d in size = %d out size = %d out rate = %f",
cur_iteration, audioscale->gst_resample_template.channels,
GST_BUFFER_SIZE (buf), GST_BUFFER_SIZE (outbuf), outrate);
curoffset = 0;
for (i = 0; i < GST_BUFFER_SIZE (buf) / (sizeof (gint16));
i += audioscale->gst_resample_template.channels) {
for (j = 0; j < audioscale->gst_resample_template.channels; j++) {
outdata[curoffset] = indata[i + j];
outdata[curoffset + audioscale->gst_resample_template.channels] =
indata[i + j];
curoffset++;
}
curoffset += audioscale->gst_resample_template.channels;
}
GST_BUFFER_DATA (outbuf) = (gpointer) outdata;
GST_BUFFER_TIMESTAMP (outbuf) =
audioscale->offsets[cur_iteration] * GST_SECOND / outrate;
audioscale->offsets[cur_iteration] +=
GST_BUFFER_SIZE (outbuf) / sizeof (gint16) /
audioscale->gst_resample->channels;
return outbuf;
}
static void
gst_audioscale_init (Audioscale * audioscale)
{
gst_resample_t *r;
audioscale->num_iterations = 1;
audioscale->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_audioscale_sink_template), "sink");
gst_element_add_pad (GST_ELEMENT (audioscale), audioscale->sinkpad);
gst_pad_set_chain_function (audioscale->sinkpad, gst_audioscale_chain);
gst_pad_set_link_function (audioscale->sinkpad, gst_audioscale_link);
gst_pad_set_getcaps_function (audioscale->sinkpad, gst_audioscale_getcaps);
gst_pad_set_fixate_function (audioscale->sinkpad, gst_audioscale_fixate);
audioscale->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_audioscale_src_template), "src");
gst_element_add_pad (GST_ELEMENT (audioscale), audioscale->srcpad);
gst_pad_set_link_function (audioscale->srcpad, gst_audioscale_link);
gst_pad_set_getcaps_function (audioscale->srcpad, gst_audioscale_getcaps);
gst_pad_set_fixate_function (audioscale->srcpad, gst_audioscale_fixate);
r = &(audioscale->gst_resample_template);
r->priv = audioscale;
r->get_buffer = gst_audioscale_get_buffer;
r->method = GST_RESAMPLE_SINC;
r->channels = 0;
r->filter_length = 16;
r->i_rate = -1;
r->o_rate = -1;
r->format = GST_RESAMPLE_S16;
/*r->verbose = 1; */
audioscale->gst_resample = NULL;
audioscale->outbuf = NULL;
audioscale->offsets = NULL;
audioscale->gst_resample_offset = 0;
audioscale->increase = FALSE;
GST_OBJECT_FLAG_SET (audioscale, GST_ELEMENT_EVENT_AWARE);
}
static void
gst_audioscale_dispose (GObject * object)
{
Audioscale *audioscale = GST_AUDIOSCALE (object);
if (audioscale->gst_resample) {
gst_resample_close (audioscale->gst_resample);
g_free (audioscale->gst_resample);
audioscale->gst_resample = NULL;
}
if (audioscale->offsets) {
g_free (audioscale->offsets);
audioscale->offsets = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_audioscale_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstBuffer *tempbuf, *tempbuf2;
GstClockTime outduration;
Audioscale *audioscale;
guchar *data;
gulong size;
gint i;
double outrate;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
audioscale = GST_AUDIOSCALE (gst_pad_get_parent (pad));
if (GST_IS_EVENT (_data)) {
GstEvent *e = GST_EVENT (_data);
switch (GST_EVENT_TYPE (e)) {
case GST_EVENT_DISCONTINUOUS:{
gint64 new_off = 0;
if (!audioscale->gst_resample) {
GST_LOG ("Discont before negotiation took place - ignoring");
} else if (gst_event_discont_get_value (e, GST_FORMAT_TIME, &new_off)) {
/* time -> out-sample */
new_off = new_off * audioscale->gst_resample->o_rate / GST_SECOND;
} else if (gst_event_discont_get_value (e,
GST_FORMAT_DEFAULT, &new_off)) {
/* in-sample -> out-sample */
new_off *= audioscale->gst_resample->o_rate;
new_off /= audioscale->gst_resample->i_rate;
} else if (gst_event_discont_get_value (e, GST_FORMAT_BYTES, &new_off)) {
new_off /= audioscale->gst_resample->channels;
new_off /=
(audioscale->gst_resample->format == GST_RESAMPLE_S16) ? 2 : 4;
new_off *= audioscale->gst_resample->o_rate;
new_off /= audioscale->gst_resample->i_rate;
} else {
/* *sigh* */
GST_DEBUG ("Discont without value - ignoring");
}
audioscale->gst_resample_offset = new_off;
/* fall-through */
}
default:
gst_pad_event_default (pad, e);
break;
}
return;
} else if (GST_BUFFER_TIMESTAMP_IS_VALID (buf) && audioscale->gst_resample) {
/* update time for out-sample */
audioscale->gst_resample_offset = GST_BUFFER_TIMESTAMP (buf) *
audioscale->gst_resample->o_rate / GST_SECOND;
}
if (audioscale->passthru && audioscale->num_iterations == 0) {
gst_pad_push (audioscale->srcpad, GST_DATA (buf));
return;
}
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
outduration = GST_BUFFER_DURATION (buf);
GST_DEBUG ("gst_audioscale_chain: got buffer of %ld bytes in '%s'\n",
size, gst_element_get_name (GST_ELEMENT (audioscale)));
tempbuf = buf;
outrate = audioscale->gst_resample_template.i_rate;
if (audioscale->increase && !audioscale->passthru) {
GST_DEBUG ("doing gstresample");
gst_resample_scale (audioscale->gst_resample, data, size);
tempbuf = audioscale->outbuf;
gst_buffer_unref (buf);
outrate = audioscale->gst_resample->o_rate;
}
for (i = 0; i < audioscale->num_iterations; i++) {
tempbuf2 = tempbuf;
GST_DEBUG ("doing %s",
audioscale->
increase ? "gst_audioscale_increase_rate" :
"gst_audioscale_decrease_rate");
if (audioscale->increase) {
outrate *= 2;
tempbuf = gst_audioscale_increase_rate (audioscale, tempbuf, outrate, i);
} else {
outrate /= 2;
tempbuf = gst_audioscale_decrease_rate (audioscale, tempbuf, outrate, i);
}
gst_buffer_unref (tempbuf2);
data = GST_BUFFER_DATA (tempbuf);
size = GST_BUFFER_SIZE (tempbuf);
}
if (!audioscale->increase && !audioscale->passthru) {
gst_resample_scale (audioscale->gst_resample, data, size);
gst_buffer_unref (tempbuf);
tempbuf = audioscale->outbuf;
}
GST_BUFFER_DURATION (tempbuf) = outduration;
gst_pad_push (audioscale->srcpad, GST_DATA (tempbuf));
}
static GstStateChangeReturn
gst_audioscale_change_state (GstElement * element, GstStateChange transition)
{
Audioscale *audioscale = GST_AUDIOSCALE (element);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
audioscale->gst_resample_offset = 0;
break;
default:
break;
}
return parent_class->change_state (element, transition);
}
static void
gst_audioscale_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
Audioscale *src;
gst_resample_t *r;
g_return_if_fail (GST_IS_AUDIOSCALE (object));
src = GST_AUDIOSCALE (object);
r = &(src->gst_resample_template);
switch (prop_id) {
case ARG_FILTERLEN:
r->filter_length = g_value_get_int (value);
GST_DEBUG_OBJECT (GST_ELEMENT (src), "new filter length %d\n",
r->filter_length);
break;
case ARG_METHOD:
r->method = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
gst_resample_reinit (r);
}
static void
gst_audioscale_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
Audioscale *src;
gst_resample_t *r;
src = GST_AUDIOSCALE (object);
r = &(src->gst_resample_template);
switch (prop_id) {
case ARG_FILTERLEN:
g_value_set_int (value, r->filter_length);
break;
case ARG_METHOD:
g_value_set_enum (value, r->method);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_element_register (plugin, "audioscale", GST_RANK_SECONDARY,
GST_TYPE_AUDIOSCALE)) {
return FALSE;
}
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"audioscale",
"Resamples audio", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
GST_PACKAGE_ORIGIN)

View file

@ -1,81 +0,0 @@
/* 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 __AUDIOSCALE_H__
#define __AUDIOSCALE_H__
#include <gst/gst.h>
#include <gst/resample/resample.h>
G_BEGIN_DECLS
#define GST_TYPE_AUDIOSCALE \
(audioscale_get_type())
#define GST_AUDIOSCALE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIOSCALE,Audioscale))
#define GST_AUDIOSCALE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIOSCALE,Audioscale))
#define GST_IS_AUDIOSCALE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIOSCALE))
#define GST_IS_AUDIOSCALE_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIOSCALE))
typedef enum {
GST_AUDIOSCALE_NEAREST,
GST_AUDIOSCALE_BILINEAR,
GST_AUDIOSCALE_SINC,
} GstAudioScaleMethod;
typedef struct _Audioscale Audioscale;
typedef struct _AudioscaleClass AudioscaleClass;
struct _Audioscale {
GstElement element;
GstPad *sinkpad,*srcpad;
/* audio state */
gboolean passthru;
gint64 gst_resample_offset;
gint64* offsets;
gboolean increase; /* is the rate change an increase */
gint num_iterations; /* number of iterations through gst_audioscale/(increase|decrease)_rate */
gst_resample_t gst_resample_template;
gst_resample_t* gst_resample;
GstBuffer* outbuf;
};
struct _AudioscaleClass {
GstElementClass parent_class;
};
GType gst_audioscale_get_type(void);
G_END_DECLS
#endif /* __AUDIOSCALE_H__ */

View file

@ -1,118 +0,0 @@
/* 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 __PRIVATE_H__
#define __PRIVATE_H__
#include "resample.h"
G_BEGIN_DECLS
void gst_resample_nearest_s16(gst_resample_t *r);
void gst_resample_bilinear_s16(gst_resample_t *r);
void gst_resample_sinc_s16(gst_resample_t *r);
void gst_resample_sinc_slow_s16(gst_resample_t *r);
void gst_resample_sinc_ft_s16(gst_resample_t * r);
void gst_resample_nearest_float(gst_resample_t *r);
void gst_resample_bilinear_float(gst_resample_t *r);
void gst_resample_sinc_float(gst_resample_t *r);
void gst_resample_sinc_slow_float(gst_resample_t *r);
void gst_resample_sinc_ft_float(gst_resample_t * r);
typedef struct functable_s functable_t;
struct functable_s {
double start;
double offset;
int len;
double invoffset;
double scale;
double scale2;
double (*func_x)(void *,double x);
double (*func_dx)(void *,double x);
double (*func2_x)(void *,double x);
double (*func2_dx)(void *,double x);
double *fx;
double *fdx;
void *priv;
};
void functable_init(functable_t *t);
double functable_eval(functable_t *t,double x);
double functable_fir(functable_t *t,double x0,int n,double *data,int len);
void functable_fir2(functable_t *t,double *r0, double *r1, double x0,
int n,double *data,int len);
double functable_sinc(void *p, double x);
double functable_dsinc(void *p, double x);
double functable_window_std(void *p, double x);
double functable_window_dstd(void *p, double x);
double functable_window_boxcar(void *p, double x);
double functable_window_dboxcar(void *p, double x);
/* math lib stuff */
void conv_double_short_table(double *dest, short *src, int n);
void conv_double_short_unroll(double *dest, short *src, int n);
void conv_double_short_ref(double *dest, short *src, int n);
#ifdef HAVE_CPU_PPC
void conv_double_short_altivec(double *dest, short *src, int n);
#endif
void conv_short_double_ref(short *dest, double *src, int n);
#ifdef HAVE_CPU_PPC
void conv_short_double_ppcasm(short *dest, double *src, int n);
#endif
#ifdef HAVE_CPU_PPC
# define conv_double_short conv_double_short_table
# if 0
/* disabled as in .c */
# define conv_short_double conv_short_double_ppcasm
# else
# define conv_short_double conv_short_double_ref
# endif
#else
# define conv_double_short conv_double_short_ref
# define conv_short_double conv_short_double_ref
#endif
#define conv_double_float conv_double_float_ref
#define conv_float_double conv_float_double_ref
void conv_double_short_dstr(double *dest, short *src, int n, int dstr);
void conv_short_double_sstr(short *dest, double *src, int n, int dstr);
void conv_double_float_ref(double *dest, float *src, int n);
void conv_float_double_ref(float *dest, double *src, int n);
void conv_double_float_dstr(double *dest, float *src, int n, int dstr);
void conv_float_double_sstr(float *dest, double *src, int n, int sstr);
G_END_DECLS
#endif /* __PRIVATE_H__ */

View file

@ -1,929 +0,0 @@
/* 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 "private.h"
#include <gst/gstplugin.h>
#include <gst/gstversion.h>
inline double
sinc (double x)
{
if (x == 0)
return 1;
return sin (x) / x;
}
inline double
window_func (double x)
{
x = 1 - x * x;
return x * x;
}
signed short
double_to_s16 (double x)
{
if (x < -32768) {
printf ("clipped\n");
return -32768;
}
if (x > 32767) {
printf ("clipped\n");
return -32767;
}
return rint (x);
}
signed short
double_to_s16_ppcasm (double x)
{
if (x < -32768) {
return -32768;
}
if (x > 32767) {
return -32767;
}
return rint (x);
}
void
gst_resample_init (gst_resample_t * r)
{
r->i_start = 0;
if (r->filter_length & 1) {
r->o_start = 0;
} else {
r->o_start = r->o_inc * 0.5;
}
memset (r->acc, 0, sizeof (r->acc));
gst_resample_reinit (r);
}
void
gst_resample_reinit (gst_resample_t * 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 == GST_RESAMPLE_S16) {
switch (r->method) {
default:
case GST_RESAMPLE_NEAREST:
r->scale = gst_resample_nearest_s16;
break;
case GST_RESAMPLE_BILINEAR:
r->scale = gst_resample_bilinear_s16;
break;
case GST_RESAMPLE_SINC_SLOW:
r->scale = gst_resample_sinc_s16;
break;
case GST_RESAMPLE_SINC:
r->scale = gst_resample_sinc_ft_s16;
break;
}
} else if (r->format == GST_RESAMPLE_FLOAT) {
switch (r->method) {
default:
case GST_RESAMPLE_NEAREST:
r->scale = gst_resample_nearest_float;
break;
case GST_RESAMPLE_BILINEAR:
r->scale = gst_resample_bilinear_float;
break;
case GST_RESAMPLE_SINC_SLOW:
r->scale = gst_resample_sinc_float;
break;
case GST_RESAMPLE_SINC:
r->scale = gst_resample_sinc_ft_float;
break;
}
} else {
fprintf (stderr, "gst_resample: Unexpected format \"%d\"\n", r->format);
}
}
void
gst_resample_close (gst_resample_t * r)
{
if (r->buffer) {
free (r->buffer);
r->buffer = NULL;
r->buffer_len = 0;
}
if (r->hack_union.s.out_tmp) {
free (r->hack_union.s.out_tmp);
r->hack_union.s.out_tmp = NULL;
r->hack_union.s.out_tmp_len = 0;
}
}
/*
* Prepare to be confused.
*
* We keep a "timebase" that is based on output samples. The zero
* of the timebase cooresponds 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.
*/
void
gst_resample_scale (gst_resample_t * r, void *i_buf, unsigned int i_size)
{
int o_size;
r->i_buf = i_buf;
r->i_samples = i_size / 2 / r->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->channels * 2;
r->o_buf = r->get_buffer (r->priv, o_size);
if (r->verbose) {
printf ("gst_resample_scale: i_buf=%p i_size=%d\n", i_buf, i_size);
printf ("gst_resample_scale: i_samples=%d o_samples=%d i_inc=%g o_buf=%p\n",
r->i_samples, r->o_samples, r->i_inc, r->o_buf);
printf ("gst_resample_scale: i_start=%g i_end=%g o_start=%g\n",
r->i_start, r->i_end, r->o_start);
}
if ((r->filter_length + r->i_samples) * sizeof (double) * 2 > r->buffer_len) {
int size = (r->filter_length + r->i_samples) * sizeof (double) * 2;
if (r->verbose) {
printf ("gst_resample temp buffer size=%d\n", size);
}
if (r->buffer)
free (r->buffer);
r->buffer_len = size;
r->buffer = malloc (size);
memset (r->buffer, 0, size);
}
if (r->format == GST_RESAMPLE_S16) {
if (r->channels == 2) {
conv_double_short (r->buffer + r->filter_length * sizeof (double) * 2,
r->i_buf, r->i_samples * 2);
} else {
conv_double_short_dstr (r->buffer +
r->filter_length * sizeof (double) * 2, r->i_buf, r->i_samples,
sizeof (double) * 2);
}
} else if (r->format == GST_RESAMPLE_FLOAT) {
if (r->channels == 2) {
conv_double_float (r->buffer + r->filter_length * sizeof (double) * 2,
r->i_buf, r->i_samples * 2);
} else {
conv_double_float_dstr (r->buffer +
r->filter_length * sizeof (double) * 2, r->i_buf, r->i_samples,
sizeof (double) * 2);
}
}
r->scale (r);
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;
}
void
gst_resample_nearest_s16 (gst_resample_t * r)
{
signed short *i_ptr, *o_ptr;
int i_count = 0;
double a;
int i;
i_ptr = (signed short *) r->i_buf;
o_ptr = (signed short *) r->o_buf;
a = r->o_start;
i_count = 0;
#define SCALE_LOOP(COPY,INC) \
for (i = 0; i < r->o_samples; i++) { \
COPY; \
a += r->o_inc; \
while (a >= 1) { \
a -= 1; \
i_ptr+=INC; \
i_count++; \
} \
o_ptr+=INC; \
}
switch (r->channels) {
case 1:
SCALE_LOOP (o_ptr[0] = i_ptr[0], 1);
break;
case 2:
SCALE_LOOP (o_ptr[0] = i_ptr[0];
o_ptr[1] = i_ptr[1], 2);
break;
default:
{
int n, n_chan = r->channels;
SCALE_LOOP (for (n = 0; n < n_chan; n++) o_ptr[n] = i_ptr[n], n_chan);
}
}
if (i_count != r->i_samples) {
printf ("handled %d in samples (expected %d)\n", i_count, r->i_samples);
}
}
void
gst_resample_bilinear_s16 (gst_resample_t * r)
{
signed short *i_ptr, *o_ptr;
int o_count = 0;
double b;
int i;
double acc0, acc1;
i_ptr = (signed short *) r->i_buf;
o_ptr = (signed short *) r->o_buf;
acc0 = r->acc[0];
acc1 = r->acc[1];
b = r->i_start;
for (i = 0; i < r->i_samples; i++) {
b += r->i_inc;
/*printf("in %d\n",i_ptr[0]); */
if (b >= 2) {
printf ("not expecting b>=2\n");
}
if (b >= 1) {
acc0 += (1.0 - (b - r->i_inc)) * i_ptr[0];
acc1 += (1.0 - (b - r->i_inc)) * i_ptr[1];
o_ptr[0] = rint (acc0);
/*printf("out %d\n",o_ptr[0]); */
o_ptr[1] = rint (acc1);
o_ptr += 2;
o_count++;
b -= 1.0;
acc0 = b * i_ptr[0];
acc1 = b * i_ptr[1];
} else {
acc0 += i_ptr[0] * r->i_inc;
acc1 += i_ptr[1] * r->i_inc;
}
i_ptr += 2;
}
r->acc[0] = acc0;
r->acc[1] = acc1;
if (o_count != r->o_samples) {
printf ("handled %d out samples (expected %d)\n", o_count, r->o_samples);
}
}
void
gst_resample_sinc_slow_s16 (gst_resample_t * 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->channels;
printf ("gst_resample temp buffer\n");
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);
/*printf("j %d sin %g cos %g\n",j,sinx,cosx); */
/*printf("j %d sin %g x %g sinc %g\n",j,sinx,x,weight); */
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->channels,
r->filter_length * 2 * r->channels);
}
/* only works for channels == 2 ???? */
void
gst_resample_sinc_s16 (gst_resample_t * 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);
/*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */
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;
}
}
/*
* 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 functable_t *ft;
void
gst_resample_sinc_ft_s16 (gst_resample_t * 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;
double *out_tmp;
if (r->hack_union.s.out_tmp_len < r->o_samples) {
r->hack_union.s.out_tmp = realloc (r->hack_union.s.out_tmp,
r->o_samples * 2 * sizeof (double));
r->hack_union.s.out_tmp_len = r->o_samples;
}
out_tmp = r->hack_union.s.out_tmp;
scale = r->i_inc; /* cutoff at 22050 */
/*scale = 1.0; // cutoff at 24000 */
/*scale = r->i_inc * 0.5; // cutoff at 11025 */
if (!ft) {
ft = malloc (sizeof (*ft));
memset (ft, 0, sizeof (*ft));
ft->len = (r->filter_length + 2) * n;
ft->offset = 1.0 / n;
ft->start = -ft->len * 0.5 * ft->offset;
ft->func_x = functable_sinc;
ft->func_dx = functable_dsinc;
ft->scale = M_PI * scale;
ft->func2_x = functable_window_std;
ft->func2_dx = functable_window_dstd;
ft->scale2 = 1.0 / r->halftaps;
functable_init (ft);
/*printf("len=%d offset=%g start=%g\n",ft->len,ft->offset,ft->start); */
}
ptr = r->buffer;
o_ptr = (signed short *) r->o_buf;
center = r->o_start;
while (center - r->halftaps < -1 * r->filter_length)
center += 1.0;
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); */
/*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */
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 (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 (ft,
&c0, &c1, x, n, ptr + (start + r->filter_length) * 2, r->filter_length);
c0 *= scale;
c1 *= scale;
#endif
out_tmp[2 * i + 0] = c0;
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++;
}
}
if (r->channels == 2) {
conv_short_double (r->o_buf, out_tmp, 2 * r->o_samples);
} else {
conv_short_double_sstr (r->o_buf, out_tmp, r->o_samples,
2 * sizeof (double));
}
}
/********
** float code below
********/
void
gst_resample_nearest_float (gst_resample_t * r)
{
float *i_ptr, *o_ptr;
int i_count = 0;
double a;
int i;
i_ptr = (float *) r->i_buf;
o_ptr = (float *) r->o_buf;
a = r->o_start;
i_count = 0;
#define SCALE_LOOP(COPY,INC) \
for (i = 0; i < r->o_samples; i++) { \
COPY; \
a += r->o_inc; \
while (a >= 1) { \
a -= 1; \
i_ptr+=INC; \
i_count++; \
} \
o_ptr+=INC; \
}
switch (r->channels) {
case 1:
SCALE_LOOP (o_ptr[0] = i_ptr[0], 1);
break;
case 2:
SCALE_LOOP (o_ptr[0] = i_ptr[0];
o_ptr[1] = i_ptr[1], 2);
break;
default:
{
int n, n_chan = r->channels;
SCALE_LOOP (for (n = 0; n < n_chan; n++) o_ptr[n] = i_ptr[n], n_chan);
}
}
if (i_count != r->i_samples) {
printf ("handled %d in samples (expected %d)\n", i_count, r->i_samples);
}
}
void
gst_resample_bilinear_float (gst_resample_t * r)
{
float *i_ptr, *o_ptr;
int o_count = 0;
double b;
int i;
double acc0, acc1;
i_ptr = (float *) r->i_buf;
o_ptr = (float *) r->o_buf;
acc0 = r->acc[0];
acc1 = r->acc[1];
b = r->i_start;
for (i = 0; i < r->i_samples; i++) {
b += r->i_inc;
/*printf("in %d\n",i_ptr[0]); */
if (b >= 2) {
printf ("not expecting b>=2\n");
}
if (b >= 1) {
acc0 += (1.0 - (b - r->i_inc)) * i_ptr[0];
acc1 += (1.0 - (b - r->i_inc)) * i_ptr[1];
o_ptr[0] = acc0;
/*printf("out %d\n",o_ptr[0]); */
o_ptr[1] = acc1;
o_ptr += 2;
o_count++;
b -= 1.0;
acc0 = b * i_ptr[0];
acc1 = b * i_ptr[1];
} else {
acc0 += i_ptr[0] * r->i_inc;
acc1 += i_ptr[1] * r->i_inc;
}
i_ptr += 2;
}
r->acc[0] = acc0;
r->acc[1] = acc1;
if (o_count != r->o_samples) {
printf ("handled %d out samples (expected %d)\n", o_count, r->o_samples);
}
}
void
gst_resample_sinc_slow_float (gst_resample_t * r)
{
float *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 * sizeof (float) * r->channels;
printf ("gst_resample temp buffer\n");
r->buffer = malloc (size);
memset (r->buffer, 0, size);
}
i_ptr = (float *) r->i_buf;
o_ptr = (float *) r->o_buf;
a = r->i_start;
#define GETBUF(index,chan) (((index)<0) \
? ((float *)(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);
/*printf("j %d sin %g cos %g\n",j,sinx,cosx); */
/*printf("j %d sin %g x %g sinc %g\n",j,sinx,x,weight); */
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] = c0;
o_ptr[1] = c1;
o_ptr += 2;
a += r->o_inc;
}
}
#undef GETBUF
memcpy (r->buffer,
i_ptr + (r->i_samples - r->filter_length) * r->channels,
r->filter_length * sizeof (float) * r->channels);
}
/* only works for channels == 2 ???? */
void
gst_resample_sinc_float (gst_resample_t * r)
{
double *ptr;
float *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 = (float *) 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);
/*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */
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] = c0;
o_ptr[1] = c1;
o_ptr += 2;
}
}
void
gst_resample_sinc_ft_float (gst_resample_t * r)
{
double *ptr;
float *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;
double *out_tmp;
if (r->hack_union.s.out_tmp_len < r->o_samples) {
r->hack_union.s.out_tmp = realloc (r->hack_union.s.out_tmp,
r->o_samples * 2 * sizeof (double));
r->hack_union.s.out_tmp_len = r->o_samples;
}
out_tmp = r->hack_union.s.out_tmp;
scale = r->i_inc; /* cutoff at 22050 */
/*scale = 1.0; // cutoff at 24000 */
/*scale = r->i_inc * 0.5; // cutoff at 11025 */
if (!ft) {
ft = malloc (sizeof (*ft));
memset (ft, 0, sizeof (*ft));
ft->len = (r->filter_length + 2) * n;
ft->offset = 1.0 / n;
ft->start = -ft->len * 0.5 * ft->offset;
ft->func_x = functable_sinc;
ft->func_dx = functable_dsinc;
ft->scale = M_PI * scale;
ft->func2_x = functable_window_std;
ft->func2_dx = functable_window_dstd;
ft->scale2 = 1.0 / r->halftaps;
functable_init (ft);
/*printf("len=%d offset=%g start=%g\n",ft->len,ft->offset,ft->start); */
}
ptr = r->buffer;
o_ptr = (float *) 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); */
/*printf("%d: a=%g start=%d end=%d\n",i,a,start,start+r->filter_length-1); */
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 (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 (ft,
&c0, &c1, x, n, ptr + (start + r->filter_length) * 2, r->filter_length);
c0 *= scale;
c1 *= scale;
#endif
out_tmp[2 * i + 0] = c0;
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++;
}
}
if (r->channels == 2) {
conv_float_double (r->o_buf, out_tmp, 2 * r->o_samples);
} else {
conv_float_double_sstr (r->o_buf, out_tmp, r->o_samples,
2 * sizeof (double));
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"gstresample",
"Resampling routines for use in audio plugins",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);

View file

@ -1,111 +0,0 @@
/* 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 __GST_RESAMPLE_H__
#define __GST_RESAMPLE_H__
#include <glib.h>
G_BEGIN_DECLS
typedef enum {
GST_RESAMPLE_NEAREST = 0,
GST_RESAMPLE_BILINEAR,
GST_RESAMPLE_SINC_SLOW,
GST_RESAMPLE_SINC,
} gst_resample_method;
typedef enum {
GST_RESAMPLE_S16 = 0,
GST_RESAMPLE_FLOAT
} gst_resample_format;
typedef struct gst_resample_s gst_resample_t;
struct gst_resample_s {
/* parameters */
gst_resample_method method;
int channels;
int verbose;
gst_resample_format format;
int filter_length;
double i_rate;
double o_rate;
void *priv;
void *(*get_buffer)(void *priv, unsigned int size);
/* internal parameters */
double halftaps;
/* filter state */
void *buffer;
int buffer_len;
double i_start;
double o_start;
double i_start_buf;
double i_end_buf;
double i_inc;
double o_inc;
double i_end;
double o_end;
int i_samples;
int o_samples;
void *i_buf, *o_buf;
double acc[2];
union {
struct {
double *out_tmp;
int out_tmp_len;
} s;
double padding[8];
} hack_union;
/* methods */
void (*scale)(gst_resample_t *r);
double ack;
};
void gst_resample_init(gst_resample_t *r);
void gst_resample_reinit(gst_resample_t *r);
void gst_resample_close (gst_resample_t * r);
void gst_resample_scale(gst_resample_t *r, void *i_buf, unsigned int size);
G_END_DECLS
#endif /* __GST_RESAMPLE_H__ */

View file

@ -1,375 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include <resample.h>
#define AMP 16000
#define I_RATE 48000
#define O_RATE 44100
/*#define O_RATE 24000 */
/*#define test_func(x) 1 */
/*#define test_func(x) sin(2*M_PI*(x)*10) */
/*#define test_func(x) sin(2*M_PI*(x)*(x)*1000) */
#define test_func(x) sin(2*M_PI*(x)*(x)*12000)
short i_buf[I_RATE * 2 * 2];
short o_buf[O_RATE * 2 * 2];
static int i_offset;
static int o_offset;
FILE *out;
void test_res1 (void);
void test_res2 (void);
void test_res3 (void);
void test_res4 (void);
void test_res5 (void);
void test_res6 (void);
void test_res7 (void);
int
main (int argc, char *argv[])
{
out = fopen ("out", "w");
test_res7 ();
return 0;
}
void *
get_buffer (void *priv, unsigned int size)
{
void *ret;
ret = ((void *) o_buf) + o_offset;
o_offset += size;
return ret;
}
struct timeval start_time;
void
start_timer (void)
{
gettimeofday (&start_time, NULL);
/*printf("start %ld.%06ld\n",start_time.tv_sec,start_time.tv_usec); */
}
void
end_timer (void)
{
struct timeval end_time;
double diff;
gettimeofday (&end_time, NULL);
/*printf("end %ld.%06ld\n",end_time.tv_sec,end_time.tv_usec); */
diff = (end_time.tv_sec - start_time.tv_sec) +
1e-6 * (end_time.tv_usec - start_time.tv_usec);
printf ("time %g\n", diff);
}
void
test_res1 (void)
{
resample_t *r;
int i;
double sum10k, sum22k;
double f;
int n10k, n22k;
double x;
for (i = 0; i < I_RATE; i++) {
i_buf[i * 2 + 0] = rint (AMP * test_func ((double) i / I_RATE));
/*i_buf[i*2+1] = rint(AMP * test_func((double)i/I_RATE)); */
i_buf[i * 2 + 1] = (i < 1000) ? AMP : 0;
}
r = malloc (sizeof (resample_t));
memset (r, 0, sizeof (resample_t));
r->i_rate = I_RATE;
r->o_rate = O_RATE;
/*r->method = RESAMPLE_SINC_SLOW; */
r->method = RESAMPLE_SINC;
r->channels = 2;
/*r->verbose = 1; */
r->filter_length = 64;
r->get_buffer = get_buffer;
resample_init (r);
start_timer ();
#define blocked
#ifdef blocked
for (i = 0; i + 256 < I_RATE; i += 256) {
resample_scale (r, i_buf + i * 2, 256 * 2 * 2);
}
if (I_RATE - i) {
resample_scale (r, i_buf + i * 2, (I_RATE - i) * 2 * 2);
}
#else
resample_scale (r, i_buf, I_RATE * 2 * 2);
#endif
end_timer ();
for (i = 0; i < O_RATE; i++) {
f = AMP * test_func ((double) i / O_RATE);
/*f = rint(AMP*test_func((double)i/O_RATE)); */
fprintf (out, "%d %d %d %g %g\n", i,
o_buf[2 * i + 0], o_buf[2 * i + 1], f, o_buf[2 * i + 0] - f);
}
sum10k = 0;
sum22k = 0;
n10k = 0;
n22k = 0;
for (i = 0; i < O_RATE; i++) {
f = AMP * test_func ((double) i / O_RATE);
/*f = rint(AMP*test_func((double)i/O_RATE)); */
x = o_buf[2 * i + 0] - f;
if (((0.5 * i) / O_RATE * I_RATE) < 10000) {
sum10k += x * x;
n10k++;
}
if (((0.5 * i) / O_RATE * I_RATE) < 22050) {
sum22k += x * x;
n22k++;
}
}
printf ("average error 10k=%g 22k=%g\n",
sqrt (sum10k / n10k), sqrt (sum22k / n22k));
}
void
test_res2 (void)
{
functable_t *t;
int i;
double x;
double f1, f2;
t = malloc (sizeof (*t));
memset (t, 0, sizeof (*t));
t->start = -50.0;
t->offset = 1;
t->len = 100;
t->func_x = functable_sinc;
t->func_dx = functable_dsinc;
functable_init (t);
for (i = 0; i < 1000; i++) {
x = -50.0 + 0.1 * i;
f1 = functable_sinc (NULL, x);
f2 = functable_eval (t, x);
fprintf (out, "%d %g %g %g\n", i, f1, f2, f1 - f2);
}
}
void
test_res3 (void)
{
functable_t *t;
int i;
double x;
double f1, f2;
int n = 1;
t = malloc (sizeof (*t));
memset (t, 0, sizeof (*t));
t->start = -50.0;
t->offset = 1.0 / n;
t->len = 100 * n;
t->func_x = functable_sinc;
t->func_dx = functable_dsinc;
t->func2_x = functable_window_std;
t->func2_dx = functable_window_dstd;
t->scale = 1.0;
t->scale2 = 1.0 / (M_PI * 16);
functable_init (t);
for (i = 0; i < 1000 * n; i++) {
x = -50.0 + 0.1 / n * i;
f1 = functable_sinc (NULL, t->scale * x) *
functable_window_std (NULL, t->scale2 * x);
f2 = functable_eval (t, x);
fprintf (out, "%d %g %g %g\n", i, f1, f2, f2 - f1);
}
}
double
sinc_poly (double x)
{
#define INV3FAC 1.66666666666666666e-1
#define INV5FAC 8.33333333333333333e-3
#define INV7FAC 1.984126984e-4
#define INV9FAC 2.755731922e-6
#define INV11FAC 2.505210839e-8
double x2 = x * x;
return 1 - x2 * INV3FAC + x2 * x2 * INV5FAC - x2 * x2 * x2 * INV7FAC;
/*+ x2 * x2 * x2 * x2 * INV9FAC */
/*- x2 * x2 * x2 * x2 * x2 * INV11FAC; */
}
void
test_res4 (void)
{
int i;
double x, f1, f2;
for (i = 1; i < 100; i++) {
x = 0.01 * i;
f1 = 1 - sin (x) / x;
f2 = 1 - sinc_poly (x);
fprintf (out, "%g %.20g %.20g %.20g\n", x, f1, f2, f2 - f1);
}
}
void
test_res5 (void)
{
int i;
double sum;
start_timer ();
sum = 0;
for (i = 0; i < I_RATE; i++) {
sum += i_buf[i * 2];
}
end_timer ();
i_buf[0] = sum;
}
void
short_to_double (double *d, short *x)
{
*d = *x;
}
void
short_to_float (float *f, short *x)
{
*f = *x;
}
void
float_to_double (double *f, float *x)
{
*f = *x;
}
void
double_to_short (short *f, double *x)
{
*f = *x;
}
double res6_tmp[1000];
void
test_res6 (void)
{
int i;
for (i = 0; i < I_RATE; i++) {
i_buf[i] = rint (AMP * test_func ((double) i / I_RATE));
}
conv_double_short_ref (res6_tmp, i_buf, 1000);
for (i = 0; i < 1000; i++) {
res6_tmp[i] *= 3.0;
}
conv_short_double_ppcasm (o_buf, res6_tmp, 1000);
for (i = 0; i < 1000; i++) {
fprintf (out, "%d %d %g %d\n", i, i_buf[i], res6_tmp[i], o_buf[i]);
}
}
void
test_res7 (void)
{
resample_t *r;
int i;
double sum10k, sum22k;
double f;
int n10k, n22k;
double x;
for (i = 0; i < I_RATE; i++) {
i_buf[i] = rint (AMP * test_func ((double) i / I_RATE));
}
r = malloc (sizeof (resample_t));
memset (r, 0, sizeof (resample_t));
r->i_rate = I_RATE;
r->o_rate = O_RATE;
/*r->method = RESAMPLE_SINC_SLOW; */
r->method = RESAMPLE_SINC;
r->channels = 1;
/*r->verbose = 1; */
r->filter_length = 64;
r->get_buffer = get_buffer;
resample_init (r);
start_timer ();
#define blocked
#ifdef blocked
for (i = 0; i + 256 < I_RATE; i += 256) {
resample_scale (r, i_buf + i, 256 * 2);
}
if (I_RATE - i) {
resample_scale (r, i_buf + i, (I_RATE - i) * 2);
}
#else
resample_scale (r, i_buf, I_RATE * 2);
#endif
end_timer ();
for (i = 0; i < O_RATE; i++) {
f = AMP * test_func ((double) i / O_RATE);
/*f = rint(AMP*test_func((double)i/O_RATE)); */
fprintf (out, "%d %d %d %g %g\n", i, o_buf[i], 0, f, o_buf[i] - f);
}
sum10k = 0;
sum22k = 0;
n10k = 0;
n22k = 0;
for (i = 0; i < O_RATE; i++) {
f = AMP * test_func ((double) i / O_RATE);
/*f = rint(AMP*test_func((double)i/O_RATE)); */
x = o_buf[i] - f;
if (((0.5 * i) / O_RATE * I_RATE) < 10000) {
sum10k += x * x;
n10k++;
}
if (((0.5 * i) / O_RATE * I_RATE) < 22050) {
sum22k += x * x;
n22k++;
}
}
printf ("average error 10k=%g 22k=%g\n",
sqrt (sum10k / n10k), sqrt (sum22k / n22k));
}