mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
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:
parent
573b0b8166
commit
8be52e0b73
14 changed files with 17 additions and 3193 deletions
17
ChangeLog
17
ChangeLog
|
@ -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:
|
||||
|
|
7
gst/audioscale/.gitignore
vendored
7
gst/audioscale/.gitignore
vendored
|
@ -1,7 +0,0 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
|
@ -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)
|
|
@ -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...
|
||||
|
|
@ -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;"../../gst-libs";../../../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;"../../gst-libs";../../../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>
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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);
|
|
@ -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__ */
|
|
@ -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));
|
||||
}
|
Loading…
Reference in a new issue