All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Replace libsamplerate resampler with libavcodec
       [not found] <20070219060932.GA24147@kain.us>
@ 2007-02-19  6:14 ` Nicholas Kain
  2007-02-19 11:12   ` Takashi Iwai
  0 siblings, 1 reply; 5+ messages in thread
From: Nicholas Kain @ 2007-02-19  6:14 UTC (permalink / raw)
  To: alsa-devel

libsamplerate does a nice job of upsampling audio while retaining quality, but
is rather inefficient and is GPL-licensed.  libavcodec includes a resampler of
equivalent quality that is about an order of magnitude faster in my tests.

ALSA is already using libavcodec for its a52 plugin, but it is important to
note that the a52 code in libavcodec is one of a few parts in lavc that is
licensed under the GPL.  The resampling code is LGPL licensed, so it's
available under much more flexible terms.

I've written a patch that replaces the use of libsamplerate with libavcodec's
resampler.  It is currently a drop-in replacement that uses the exact same
interfaces and dynamically links to libavcodec.  It is easily possible to pull
the LGPL resampling code out of libavcodec and include it directly with the
plugin if that is desirable -- it would not require invasive modifications --
but I have not done so yet.

Direct performance comparison:
a64@1GHz, x86-64 kernel/userspace, emu10k card
source: Signed 16 bit Little Endian, Rate 44100 Hz, Stereo

hardware baseline: 0.21s user 0.01s system 0% cpu 40.801 total

libsamplerate sinc_fastest: 3.02s user 0.05s system 7% cpu 40.831 total
libavcodec default: 0.55s user 0.03s system 1% cpu 40.823 total

libsamplerate best: 13.62s user 0.11s system 33% cpu 40.915 total
libavcodec best: 0.81s user 0.02s system 2% cpu 40.892 total

Note that 'libavcodec best' is not entirely fair -- libavcodec's resampler
dynamically builds a polyphase filter at startup time (which is of course
included in these benchmarks -- I'm just using 'time aplay').  The parameters
of this filter are configurable, so quality can be user configured.  That said,
I haven't found a good way to grab configuration information from .asoundrc
with a rate plugin, so currently only presets are available.

Also, it's worth noting that lavc does its resampling using fixed point math,
whereas libsamplerate uses floating point extensively.  On very low-end
machines, this will yield an even greater performance difference than is seen
here.

Please CC any responses since I'm not subscribed to the list.


diff -purN alsa-plugins-1.0.14rc2/configure.in
alsa-plugins-1.0.14rc2-nk/configure.in
--- alsa-plugins-1.0.14rc2/configure.in 2007-01-15 08:38:28.000000000 -0500
+++ alsa-plugins-1.0.14rc2-nk/configure.in      2007-02-19
00:07:02.000000000 -0500
@@ -21,9 +21,6 @@ AM_CONDITIONAL(HAVE_JACK, test x$HAVE_JA
 PKG_CHECK_MODULES(pulseaudio, [libpulse >= 0.9.2], [HAVE_PULSE=yes],
[HAVE_PULSE=no])
 AM_CONDITIONAL(HAVE_PULSE, test x$HAVE_PULSE = xyes)

-PKG_CHECK_MODULES(samplerate, [samplerate], [HAVE_SAMPLERATE=yes],
[HAVE_SAMPLERATE=no])
-AM_CONDITIONAL(HAVE_SAMPLERATE, test x$HAVE_SAMPLERATE = xyes)
-
 PKG_CHECK_MODULES(DBUS, [dbus-1], [HAVE_DBUS=yes], [HAVE_DBUS=no])
 AM_CONDITIONAL(HAVE_DBUS, test x$HAVE_DBUS = xyes)

diff -purN alsa-plugins-1.0.14rc2/Makefile.am
alsa-plugins-1.0.14rc2-nk/Makefile.am
--- alsa-plugins-1.0.14rc2/Makefile.am  2007-01-15 08:38:28.000000000 -0500
+++ alsa-plugins-1.0.14rc2-nk/Makefile.am       2007-02-19
00:10:06.000000000 -0500
@@ -4,10 +4,8 @@ endif
 if HAVE_PULSE
 PULSEDIR = pulse
 endif
-if HAVE_SAMPLERATE
-SAMPLERATEDIR = rate
-endif
 if HAVE_AVCODEC
+SAMPLERATEDIR = rate
 A52DIR = a52
 endif
 if HAVE_DBUS
diff -purN alsa-plugins-1.0.14rc2/Makefile.in
alsa-plugins-1.0.14rc2-nk/Makefile.in
--- alsa-plugins-1.0.14rc2/Makefile.in  2007-01-15 08:39:17.000000000 -0500
+++ alsa-plugins-1.0.14rc2-nk/Makefile.in       2007-02-19
00:10:48.000000000 -0500
@@ -115,8 +115,6 @@ HAVE_JACK_FALSE = @HAVE_JACK_FALSE@
 HAVE_JACK_TRUE = @HAVE_JACK_TRUE@
 HAVE_PULSE_FALSE = @HAVE_PULSE_FALSE@
 HAVE_PULSE_TRUE = @HAVE_PULSE_TRUE@
-HAVE_SAMPLERATE_FALSE = @HAVE_SAMPLERATE_FALSE@
-HAVE_SAMPLERATE_TRUE = @HAVE_SAMPLERATE_TRUE@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
@@ -194,7 +192,7 @@ sysconfdir = @sysconfdir@
 target_alias = @target_alias@
 @HAVE_JACK_TRUE@JACKDIR = jack
 @HAVE_PULSE_TRUE@PULSEDIR = pulse
-@HAVE_SAMPLERATE_TRUE@SAMPLERATEDIR = rate
+@HAVE_AVCODEC_TRUE@SAMPLERATEDIR = rate
 @HAVE_AVCODEC_TRUE@A52DIR = a52
 @HAVE_DBUS_TRUE@MAEMODIR = maemo
 SUBDIRS = oss mix $(JACKDIR) $(PULSEDIR) $(SAMPLERATEDIR) $(A52DIR)
$(MAEMODIR) doc
diff -purN alsa-plugins-1.0.14rc2/rate/Makefile.am
alsa-plugins-1.0.14rc2-nk/rate/Makefile.am
--- alsa-plugins-1.0.14rc2/rate/Makefile.am     2007-01-15
08:38:28.000000000 -0500
+++ alsa-plugins-1.0.14rc2-nk/rate/Makefile.am  2007-02-18
01:30:27.000000000 -0500
@@ -2,11 +2,11 @@ asound_module_rate_samplerate_LTLIBRARIE

 asound_module_rate_sampleratedir = $(libdir)/alsa-lib

-AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ $(samplerate_CFLAGS)
+AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @AVCODEC_CFLAGS@
 AM_LDFLAGS = -module -avoid-version -export-dynamic

 libasound_module_rate_samplerate_la_SOURCES = rate_samplerate.c
-libasound_module_rate_samplerate_la_LIBADD = @ALSA_LIBS@ @samplerate_LIBS@
+libasound_module_rate_samplerate_la_LIBADD = @ALSA_LIBS@ @AVCODEC_LIBS@

 install-exec-hook:
        rm -f $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_samplerate_*.so
diff -purN alsa-plugins-1.0.14rc2/rate/Makefile.in
alsa-plugins-1.0.14rc2-nk/rate/Makefile.in
--- alsa-plugins-1.0.14rc2/rate/Makefile.in     2007-01-15
08:39:16.000000000 -0500
+++ alsa-plugins-1.0.14rc2-nk/rate/Makefile.in  2007-02-18
01:32:25.000000000 -0500
@@ -197,10 +201,10 @@ sysconfdir = @sysconfdir@
 target_alias = @target_alias@
 asound_module_rate_samplerate_LTLIBRARIES = libasound_module_rate_samplerate.la
 asound_module_rate_sampleratedir = $(libdir)/alsa-lib
-AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ $(samplerate_CFLAGS)
+AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @AVCODEC_CFLAGS@
 AM_LDFLAGS = -module -avoid-version -export-dynamic
 libasound_module_rate_samplerate_la_SOURCES = rate_samplerate.c
-libasound_module_rate_samplerate_la_LIBADD = @ALSA_LIBS@ @samplerate_LIBS@
+libasound_module_rate_samplerate_la_LIBADD = @ALSA_LIBS@ @AVCODEC_LIBS@
 all: all-am

 .SUFFIXES:
diff -purN alsa-plugins-1.0.14rc2/rate/rate_samplerate.c
alsa-plugins-1.0.14rc2-nk/rate/rate_samplerate.c
--- alsa-plugins-1.0.14rc2/rate/rate_samplerate.c       2007-01-15
08:38:28.000000000 -0500
+++ alsa-plugins-1.0.14rc2-nk/rate/rate_samplerate.c    2007-02-18
23:59:34.000000000 -0500
@@ -1,6 +1,8 @@
 /*
- * Rate converter plugin using libsamplerate
+ * Rate converter plugin using libavcodec's resampler
+ * Copyright (c) 2007 by Nicholas Kain <njkain@gmail.com>
  *
+ * based on rate converter that uses libsamplerate
  * Copyright (c) 2006 by Takashi Iwai <tiwai@suse.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -19,80 +21,94 @@
  */

 #include <stdio.h>
-#include <samplerate.h>
 #include <alsa/asoundlib.h>
 #include <alsa/pcm_rate.h>
+#include <ffmpeg/avcodec.h>
+
+static int filter_size = 16;
+static int phase_shift = 10;
+static double cutoff = 0; /* auto-adjusts */

 struct rate_src {
-       double ratio;
-       int converter;
+       struct AVResampleContext *context;
+       int in_rate;
+       int out_rate;
+       int overflow;
+       int16_t **out;
+       int16_t **in;
        unsigned int channels;
-       float *src_buf;
-       float *dst_buf;
-       SRC_STATE *state;
-       SRC_DATA data;
 };

 static snd_pcm_uframes_t input_frames(void *obj, snd_pcm_uframes_t frames)
 {
-       struct rate_src *rate = obj;
-       if (frames == 0)
-               return 0;
-       return (snd_pcm_uframes_t)(frames * rate->ratio);
+       return frames;
 }

 static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames)
 {
-       struct rate_src *rate = obj;
-       if (frames == 0)
-               return 0;
-       return (snd_pcm_uframes_t)(frames / rate->ratio);
+       return frames;
 }

 static void pcm_src_free(void *obj)
 {
        struct rate_src *rate = obj;
+       int i;

-       free(rate->src_buf);
-       free(rate->dst_buf);
-       rate->src_buf = rate->dst_buf = NULL;
-
-       if (rate->state) {
-               src_delete(rate->state);
-               rate->state = NULL;
+       if (rate->out) {
+               for (i=0; i<rate->channels; i++) {
+                       free(rate->out[i]);
+               }
+               free(rate->out);
+       }
+       if (rate->in) {
+               for (i=0; i<rate->channels; i++) {
+                       free(rate->in[i]);
+               }
+               free(rate->in);
+       }
+       rate->out = rate->in = NULL;
+
+       if (rate->context) {
+               av_resample_close(rate->context);
+               rate->context = NULL;
        }
 }

 static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info)
 {
        struct rate_src *rate = obj;
-       int err;
+       int i;

-       if (! rate->state || rate->channels != info->channels) {
-               if (rate->state)
-                       src_delete(rate->state);
+       if (! rate->context || rate->channels != info->channels) {
+               pcm_src_free(rate);
                rate->channels = info->channels;
-               rate->state = src_new(rate->converter, rate->channels, &err);
-               if (! rate->state)
+               rate->in_rate = info->in.rate;
+               rate->out_rate = info->out.rate;
+               if (cutoff <= 0.0) {
+                       cutoff = 1.0 - 1.0/filter_size;
+                       if (cutoff < 0.80)
+                               cutoff = 0.80;
+               }
+               rate->context = av_resample_init(info->out.rate, info->in.rate,
+                       filter_size, phase_shift,
+                       (info->out.rate >= info->in.rate ? 0 : 1), cutoff);
+               if (!rate->context)
                        return -EINVAL;
        }

-       rate->ratio = (double)info->out.rate / (double)info->in.rate;
-
-       free(rate->src_buf);
-       rate->src_buf = malloc(sizeof(float) * rate->channels *
info->in.period_size);
-       free(rate->dst_buf);
-       rate->dst_buf = malloc(sizeof(float) * rate->channels *
info->out.period_size);
-       if (! rate->src_buf || ! rate->dst_buf) {
+       rate->out = malloc(rate->channels * sizeof(int16_t *));
+       rate->in = malloc(rate->channels * sizeof(int16_t *));
+       for (i=0; i<rate->channels; i++) {
+               rate->out[i] = calloc(info->out.period_size * 2,
+                       sizeof(int16_t));
+               rate->in[i] = calloc(info->in.period_size * 2,
+                       sizeof(int16_t));
+       }
+       if (!rate->out || !rate->in) {
                pcm_src_free(rate);
                return -ENOMEM;
        }

-       rate->data.data_in = rate->src_buf;
-       rate->data.data_out = rate->dst_buf;
-       rate->data.src_ratio = rate->ratio;
-       rate->data.end_of_input = 0;
-
        return 0;
 }

@@ -100,35 +116,86 @@ static int pcm_src_adjust_pitch(void *ob
 {
        struct rate_src *rate = obj;

-       rate->ratio = ((double)info->out.period_size /
(double)info->in.period_size);
-       rate->data.src_ratio = rate->ratio;
+       if (info->out.rate != rate->out_rate || info->in.rate != rate->in_rate)
+               pcm_src_init(obj, info);
        return 0;
 }

 static void pcm_src_reset(void *obj)
 {
        struct rate_src *rate = obj;
+       rate->overflow = 0;
+}

-       src_reset(rate->state);
+static void deinterleave(const int16_t *src, int16_t **dst, unsigned
int frames,
+       unsigned int chans, int overflow)
+{
+       int i, j;
+
+       if (chans == 1) {
+               memcpy(dst + overflow, src, (frames-overflow)*sizeof(int16_t));
+       } else if (chans == 2) {
+               for (j=overflow; j< (frames + overflow); j++) {
+                       dst[0][j] = *(src++);
+                       dst[1][j] = *(src++);
+               }
+       } else {
+               for (j=overflow; j< (frames + overflow); j++) {
+                       for (i=0; i<chans; i++) {
+                               dst[i][j] = *(src++);
+                       }
+               }
+       }
 }

-static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int
dst_frames,
-                               const int16_t *src, unsigned int src_frames)
+static void reinterleave(int16_t **src, int16_t *dst, unsigned int frames,
+       unsigned int chans)
+{
+       int i, j;
+
+       if (chans == 1) {
+               memcpy(dst, src, frames*sizeof(int16_t));
+       } else if (chans == 2) {
+               for (j=0; j<frames; j++) {
+                       *(dst++) = src[0][j];
+                       *(dst++) = src[1][j];
+               }
+       } else {
+               for (j=0; j<frames; j++) {
+                       for (i=0; i<chans; i++) {
+                               *(dst++) = src[i][j];
+                       }
+               }
+       }
+}
+
+static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int
+       dst_frames, const int16_t *src, unsigned int src_frames)
 {
        struct rate_src *rate = obj;
+       int consumed = 0, chans=rate->channels, ret, i, j, k=0;
+       int total_in = src_frames+rate->overflow;

-       rate->data.input_frames = src_frames;
-       rate->data.output_frames = dst_frames;
-       rate->data.end_of_input = 0;
-
-       src_short_to_float_array(src, rate->src_buf, src_frames *
rate->channels);
-       src_process(rate->state, &rate->data);
-       src_float_to_short_array(rate->dst_buf, dst, dst_frames *
rate->channels);
+       deinterleave(src, rate->in, src_frames, chans, rate->overflow);
+       for (i=0; i<chans; ++i) {
+               ret = av_resample(rate->context, rate->out[i], rate->in[i],
+                       &consumed, total_in, dst_frames, i == (chans - 1));
+               for (j=0, k=0; ret+j<dst_frames; j++) {
+                       rate->out[i][ret+j] =rate->in[i][consumed+k];
+                       if (consumed+k<src_frames)
+                               k++;
+               }
+               memmove(rate->in[i], rate->in[i]+consumed+k,
+                       (src_frames-consumed-k)*sizeof(int16_t));
+       }
+       av_resample_compensate(rate->context, src_frames-consumed, src_frames);
+       reinterleave(rate->out, dst, dst_frames, chans);
+       rate->overflow = src_frames-consumed-k;
 }

 static void pcm_src_close(void *obj)
 {
-       free(obj);
+       pcm_src_free(obj);
 }

 static snd_pcm_rate_ops_t pcm_src_ops = {
@@ -142,8 +209,8 @@ static snd_pcm_rate_ops_t pcm_src_ops =
        .output_frames = output_frames,
 };

-static int pcm_src_open(unsigned int version, void **objp,
-                       snd_pcm_rate_ops_t *ops, int type)
+int pcm_src_open(unsigned int version, void **objp, snd_pcm_rate_ops_t *ops)
+
 {
        struct rate_src *rate;

@@ -153,41 +220,47 @@ static int pcm_src_open(unsigned int ver
        }

        rate = calloc(1, sizeof(*rate));
-       if (! rate)
+       if (!rate)
                return -ENOMEM;
-       rate->converter = type;

        *objp = rate;
+       rate->context = NULL;
        *ops = pcm_src_ops;
        return 0;
 }

-int SND_PCM_RATE_PLUGIN_ENTRY(samplerate) (unsigned int version, void **objp,
-                                          snd_pcm_rate_ops_t *ops)
+int SND_PCM_RATE_PLUGIN_ENTRY(samplerate)(unsigned int version, void **objp,
+                       snd_pcm_rate_ops_t *ops)
 {
-       return pcm_src_open(version, objp, ops, SRC_SINC_FASTEST);
+       return pcm_src_open(version, objp, ops);
 }
-
-int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_best) (unsigned int version,
void **objp,
-                                               snd_pcm_rate_ops_t *ops)
+int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_best)(unsigned int version,
+                       void **objp, snd_pcm_rate_ops_t *ops)
 {
-       return pcm_src_open(version, objp, ops, SRC_SINC_BEST_QUALITY);
+       filter_size = 24;
+       phase_shift = 12;
+       return pcm_src_open(version, objp, ops);
 }
-
-int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_medium) (unsigned int
version, void **objp,
-                                                 snd_pcm_rate_ops_t *ops)
+int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_medium)(unsigned int version,
+                       void **objp, snd_pcm_rate_ops_t *ops)
 {
-       return pcm_src_open(version, objp, ops, SRC_SINC_MEDIUM_QUALITY);
+       filter_size = 20;
+       phase_shift = 11;
+       return pcm_src_open(version, objp, ops);
 }
-
-int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_order) (unsigned int
version, void **objp,
-                                                snd_pcm_rate_ops_t *ops)
+int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_order)(unsigned int version,
+                       void **objp, snd_pcm_rate_ops_t *ops)
 {
-       return pcm_src_open(version, objp, ops, SRC_ZERO_ORDER_HOLD);
+       filter_size = 12;
+       phase_shift = 8;
+       return pcm_src_open(version, objp, ops);
 }
-
-int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_linear) (unsigned int
version, void **objp,
-                                                 snd_pcm_rate_ops_t *ops)
+int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_linear)(unsigned int version,
+                       void **objp, snd_pcm_rate_ops_t *ops)
 {
-       return pcm_src_open(version, objp, ops, SRC_LINEAR);
+       filter_size = 8;
+       phase_shift = 6;
+       return pcm_src_open(version, objp, ops);
 }
+
+
--
Nicholas J. Kain <nicholas at kain dot us>
http://brightrain.aerifal.cx/~niklata/

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Replace libsamplerate resampler with libavcodec
  2007-02-19  6:14 ` [PATCH] Replace libsamplerate resampler with libavcodec Nicholas Kain
@ 2007-02-19 11:12   ` Takashi Iwai
  2007-02-19 19:49     ` Nicholas Kain
  0 siblings, 1 reply; 5+ messages in thread
From: Takashi Iwai @ 2007-02-19 11:12 UTC (permalink / raw)
  To: Nicholas Kain; +Cc: alsa-devel

At Mon, 19 Feb 2007 01:14:11 -0500,
Nicholas Kain wrote:
> 
> libsamplerate does a nice job of upsampling audio while retaining quality, but
> is rather inefficient and is GPL-licensed.  libavcodec includes a resampler of
> equivalent quality that is about an order of magnitude faster in my tests.
> 
> ALSA is already using libavcodec for its a52 plugin, but it is important to
> note that the a52 code in libavcodec is one of a few parts in lavc that is
> licensed under the GPL.  The resampling code is LGPL licensed, so it's
> available under much more flexible terms.
> 
> I've written a patch that replaces the use of libsamplerate with libavcodec's
> resampler.  It is currently a drop-in replacement that uses the exact same
> interfaces and dynamically links to libavcodec.  It is easily possible to pull
> the LGPL resampling code out of libavcodec and include it directly with the
> plugin if that is desirable -- it would not require invasive modifications --
> but I have not done so yet.

IMO, we should _add_ libavcodec resampler plugin instead of replacing
the libsamplerate one.  From the license POV, libavcodec is fairly
grey, and it's very unlikely bundled in most of linux distributions.

So, could you change your patch to add a new subdirectory and plugin?
We have already HAVE_AVCODEC conditional in configure script, hence
the addition would be pretty simple.


Thanks,

Takashi

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Replace libsamplerate resampler with libavcodec
  2007-02-19 11:12   ` Takashi Iwai
@ 2007-02-19 19:49     ` Nicholas Kain
  2007-02-20 10:56       ` Takashi Iwai
  0 siblings, 1 reply; 5+ messages in thread
From: Nicholas Kain @ 2007-02-19 19:49 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 782 bytes --]

On 2/19/07, Takashi Iwai <tiwai@suse.de> wrote:
> IMO, we should _add_ libavcodec resampler plugin instead of replacing
> the libsamplerate one.  From the license POV, libavcodec is fairly
> grey, and it's very unlikely bundled in most of linux distributions.
>
> So, could you change your patch to add a new subdirectory and plugin?
> We have already HAVE_AVCODEC conditional in configure script, hence
> the addition would be pretty simple.

Sure.  I've attached a patch that places the plugin in a rate-lavc
subdirectory.  It also provides a minimal .txt document for the plugin as
well.

I've also fixed a few minor bugs in the previous patch that were
preventing optimal quality in conversions, so if anyone has tested the
patch I sent earlier, it might be worth trying again.

[-- Attachment #2: alsa-lavc-resample3.patch --]
[-- Type: application/octet-stream, Size: 12905 bytes --]

diff -purN alsa-plugins-1.0.14rc2-clean/configure.in alsa-plugins-1.0.14rc2/configure.in
--- alsa-plugins-1.0.14rc2-clean/configure.in	2007-01-15 08:38:28.000000000 -0500
+++ alsa-plugins-1.0.14rc2/configure.in	2007-02-19 14:31:34.000000000 -0500
@@ -62,6 +62,7 @@ AC_OUTPUT([
 	mix/Makefile
 	rate/Makefile
 	a52/Makefile
+	rate-lavc/Makefile
 	maemo/Makefile
 	doc/Makefile
 ])
diff -purN alsa-plugins-1.0.14rc2-clean/doc/lavcrate.txt alsa-plugins-1.0.14rc2/doc/lavcrate.txt
--- alsa-plugins-1.0.14rc2-clean/doc/lavcrate.txt	1969-12-31 19:00:00.000000000 -0500
+++ alsa-plugins-1.0.14rc2/doc/lavcrate.txt	2007-02-19 14:31:34.000000000 -0500
@@ -0,0 +1,33 @@
+Rate Converter Plugin Using libavcodec
+======================================
+
+The plugin in rate-lavc subdirectory is an external rate converter using
+libavcodec's resampler.  You can use this rate converter plugin by defining a
+rate PCM with "converter" parameter, such as:
+
+	pcm.my_rate {
+		type rate
+		slave.pcm "hw"
+		converter "lavcrate"
+	}
+
+The plug plugin has also a similar field, "rate_converter".
+
+Or, more easily, define a global variable "defaults.pcm.rate_converter",
+which is used as the default converter type by plug and rate plugins:
+
+	defaults.pcm.rate_converter "lavcrate"
+
+Write the above in your ~/.asoundrc or /etc/asound.conf.
+
+The following converter types are available:
+
+  - lavcrate_higher		Use	length=64
+  - lavcrate_high  		Use length=32
+  - lavcrate       		Use length=16
+  - lavcrate_fast  		Use length=8
+  - lavcrate_faster		Use length=4
+
+Linear interpolation and cutoff values are automatically used depending on
+the supplied parameters and whether the plugin is used to upsample or
+downsample.
diff -purN alsa-plugins-1.0.14rc2-clean/Makefile.am alsa-plugins-1.0.14rc2/Makefile.am
--- alsa-plugins-1.0.14rc2-clean/Makefile.am	2007-01-15 08:38:28.000000000 -0500
+++ alsa-plugins-1.0.14rc2/Makefile.am	2007-02-19 14:31:34.000000000 -0500
@@ -9,12 +9,13 @@ SAMPLERATEDIR = rate
 endif
 if HAVE_AVCODEC
 A52DIR = a52
+LAVCRATEDIR = rate-lavc
 endif
 if HAVE_DBUS
 MAEMODIR = maemo
 endif
 
-SUBDIRS = oss mix $(JACKDIR) $(PULSEDIR) $(SAMPLERATEDIR) $(A52DIR) $(MAEMODIR) doc
+SUBDIRS = oss mix $(JACKDIR) $(PULSEDIR) $(SAMPLERATEDIR) $(A52DIR) $(LAVCRATEDIR) $(MAEMODIR) doc
 EXTRA_DIST = hgcompile version COPYING.GPL
 AUTOMAKE_OPTIONS = foreign
 
diff -purN alsa-plugins-1.0.14rc2-clean/Makefile.in alsa-plugins-1.0.14rc2/Makefile.in
--- alsa-plugins-1.0.14rc2-clean/Makefile.in	2007-01-15 08:39:17.000000000 -0500
+++ alsa-plugins-1.0.14rc2/Makefile.in	2007-02-19 14:31:34.000000000 -0500
@@ -60,7 +60,7 @@ RECURSIVE_TARGETS = all-recursive check-
 	uninstall-recursive
 ETAGS = etags
 CTAGS = ctags
-DIST_SUBDIRS = oss mix jack pulse rate a52 maemo doc
+DIST_SUBDIRS = oss mix jack pulse rate a52 rate-lavc maemo doc
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -196,8 +196,9 @@ target_alias = @target_alias@
 @HAVE_PULSE_TRUE@PULSEDIR = pulse
 @HAVE_SAMPLERATE_TRUE@SAMPLERATEDIR = rate
 @HAVE_AVCODEC_TRUE@A52DIR = a52
+@HAVE_AVCODEC_TRUE@LAVCRATEDIR = rate-lavc
 @HAVE_DBUS_TRUE@MAEMODIR = maemo
-SUBDIRS = oss mix $(JACKDIR) $(PULSEDIR) $(SAMPLERATEDIR) $(A52DIR) $(MAEMODIR) doc
+SUBDIRS = oss mix $(JACKDIR) $(PULSEDIR) $(SAMPLERATEDIR) $(A52DIR) $(LAVCRATEDIR) $(MAEMODIR) doc
 EXTRA_DIST = hgcompile version COPYING.GPL
 AUTOMAKE_OPTIONS = foreign
 all: config.h
diff -purN alsa-plugins-1.0.14rc2-clean/rate-lavc/gcd.h alsa-plugins-1.0.14rc2/rate-lavc/gcd.h
--- alsa-plugins-1.0.14rc2-clean/rate-lavc/gcd.h	1969-12-31 19:00:00.000000000 -0500
+++ alsa-plugins-1.0.14rc2/rate-lavc/gcd.h	2007-02-19 14:31:38.000000000 -0500
@@ -0,0 +1,41 @@
+/*
+ * Fast implementation of greatest common divisor using the binary algorithm.
+ *
+ * Copyright (c) 2007 Nicholas Kain
+ *
+ * Licensed under BSD license with no advertising clause.
+ */
+
+/* computes gcd using binary algorithm */
+static int gcd(int a, int b)
+{
+	int s,d;
+
+	if (!a || !b)
+		return a | b;
+
+	for (s=0; ((a|b)&1) == 0; ++s) {
+		a >>= 1;
+		b >>= 1;
+	}
+
+	while ((a&1) == 0)
+		a >>= 1;
+	
+	do {
+		while ((b&1) == 0) {
+			b >>= 1;
+		}
+		if (a<b) {
+			b -= a;
+		} else {
+			d = a-b;
+			a = b;
+			b = d;
+		}
+		b >>= 1;
+	} while (b);
+
+	return a << s;
+}
+
diff -purN alsa-plugins-1.0.14rc2-clean/rate-lavc/Makefile.am alsa-plugins-1.0.14rc2/rate-lavc/Makefile.am
--- alsa-plugins-1.0.14rc2-clean/rate-lavc/Makefile.am	1969-12-31 19:00:00.000000000 -0500
+++ alsa-plugins-1.0.14rc2/rate-lavc/Makefile.am	2007-02-19 14:31:34.000000000 -0500
@@ -0,0 +1,19 @@
+asound_module_rate_lavcrate_LTLIBRARIES = libasound_module_rate_lavcrate.la
+
+asound_module_rate_lavcratedir = $(libdir)/alsa-lib
+
+AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @AVCODEC_CFLAGS@
+AM_LDFLAGS = -module -avoid-version -export-dynamic
+
+libasound_module_rate_lavcrate_la_SOURCES = rate_lavcrate.c
+libasound_module_rate_lavcrate_la_LIBADD = @ALSA_LIBS@ @AVCODEC_LIBS@
+
+install-exec-hook:
+	rm -f $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_lavcrate_*.so
+	$(LN_S) libasound_module_rate_lavcrate.so $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_lavcrate_higher.so
+	$(LN_S) libasound_module_rate_lavcrate.so $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_lavcrate_high.so
+	$(LN_S) libasound_module_rate_lavcrate.so $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_lavcrate_fast.so
+	$(LN_S) libasound_module_rate_lavcrate.so $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_lavcrate_faster.so
+
+uninstall-hook:
+	rm -f $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_lavcrate_*.so
diff -purN alsa-plugins-1.0.14rc2-clean/rate-lavc/rate_lavcrate.c alsa-plugins-1.0.14rc2/rate-lavc/rate_lavcrate.c
--- alsa-plugins-1.0.14rc2-clean/rate-lavc/rate_lavcrate.c	1969-12-31 19:00:00.000000000 -0500
+++ alsa-plugins-1.0.14rc2/rate-lavc/rate_lavcrate.c	2007-02-19 14:34:26.000000000 -0500
@@ -0,0 +1,270 @@
+/*
+ * Rate converter plugin using libavcodec's resampler
+ * Copyright (c) 2007 by Nicholas Kain <njkain@gmail.com>
+ *
+ * based on rate converter that uses libsamplerate
+ * Copyright (c) 2006 by Takashi Iwai <tiwai@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <alsa/asoundlib.h>
+#include <alsa/pcm_rate.h>
+#include <ffmpeg/avcodec.h>
+#include "gcd.h"
+
+static int filter_size = 16;
+static int phase_shift = 10; /* auto-adjusts */
+static double cutoff = 0; /* auto-adjusts */
+
+struct rate_src {
+	struct AVResampleContext *context;
+	int in_rate;
+	int out_rate;
+	int stored;
+	int point;
+	int16_t **out;
+	int16_t **in;
+	unsigned int channels;
+};
+
+static snd_pcm_uframes_t input_frames(void *obj, snd_pcm_uframes_t frames)
+{
+	return frames;
+}
+
+static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames)
+{
+	return frames;
+}
+
+static void pcm_src_free(void *obj)
+{
+	struct rate_src *rate = obj;
+	int i;
+
+	if (rate->out) {
+		for (i=0; i<rate->channels; i++) {
+			free(rate->out[i]);
+		}
+		free(rate->out);
+	}
+	if (rate->in) {
+		for (i=0; i<rate->channels; i++) {
+			free(rate->in[i]);
+		}
+		free(rate->in);
+	}
+	rate->out = rate->in = NULL;
+
+	if (rate->context) {
+		av_resample_close(rate->context);
+		rate->context = NULL;
+	}
+}
+
+static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info)
+{
+	struct rate_src *rate = obj;
+	int i, ir, or;
+
+	if (! rate->context || rate->channels != info->channels) {
+		pcm_src_free(rate);
+		rate->channels = info->channels;
+		ir = rate->in_rate = info->in.rate;
+		or = rate->out_rate = info->out.rate;
+		i = gcd(or, ir);
+		if (or > ir) {
+			phase_shift = or/i;
+		} else {
+			phase_shift = ir/i;
+		}
+		if (cutoff <= 0.0) {
+			cutoff = 1.0 - 1.0/filter_size;
+			if (cutoff < 0.80)
+				cutoff = 0.80;
+		}
+		rate->context = av_resample_init(info->out.rate, info->in.rate,
+			filter_size, phase_shift,
+			(info->out.rate >= info->in.rate ? 0 : 1), cutoff);
+		if (!rate->context)
+			return -EINVAL;
+	}
+
+	rate->out = malloc(rate->channels * sizeof(int16_t *));
+	rate->in = malloc(rate->channels * sizeof(int16_t *));
+	for (i=0; i<rate->channels; i++) {
+		rate->out[i] = calloc(info->out.period_size * 2, 
+			sizeof(int16_t));
+		rate->in[i] = calloc(info->in.period_size * 2,
+			sizeof(int16_t));
+	}
+	rate->point = info->in.period_size / 2;
+	if (!rate->out || !rate->in) {
+		pcm_src_free(rate);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info)
+{
+	struct rate_src *rate = obj;
+
+	if (info->out.rate != rate->out_rate || info->in.rate != rate->in_rate)
+		pcm_src_init(obj, info);
+	return 0;
+}
+
+static void pcm_src_reset(void *obj)
+{
+	struct rate_src *rate = obj;
+	rate->stored = 0;
+}
+
+static void deinterleave(const int16_t *src, int16_t **dst, unsigned int frames,
+	unsigned int chans, int overflow)
+{
+	int i, j;
+
+	if (chans == 1) {
+		memcpy(dst + overflow, src, frames*sizeof(int16_t));
+	} else if (chans == 2) {
+		for (j=overflow; j<(frames + overflow); j++) {
+			dst[0][j] = *(src++);
+			dst[1][j] = *(src++);
+		}
+	} else {
+		for (j=overflow; j<(frames + overflow); j++) {
+			for (i=0; i<chans; i++) {
+				dst[i][j] = *(src++);
+			}
+		}
+	}
+}
+
+static void reinterleave(int16_t **src, int16_t *dst, unsigned int frames,
+	unsigned int chans)
+{
+	int i, j;
+
+	if (chans == 1) {
+		memcpy(dst, src, frames*sizeof(int16_t));
+	} else if (chans == 2) {
+		for (j=0; j<frames; j++) {
+			*(dst++) = src[0][j];
+			*(dst++) = src[1][j];
+		}
+	} else {
+		for (j=0; j<frames; j++) {
+			for (i=0; i<chans; i++) {
+				*(dst++) = src[i][j];
+			}
+		}
+	}
+}
+
+static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int
+	dst_frames, const int16_t *src, unsigned int src_frames)
+{
+	struct rate_src *rate = obj;
+	int consumed = 0, chans=rate->channels, ret=0, i;
+	int total_in = rate->stored + src_frames, new_stored;
+
+	deinterleave(src, rate->in, src_frames, chans, rate->point);
+	for (i=0; i<chans; ++i) {	
+		ret = av_resample(rate->context, rate->out[i],
+				rate->in[i]+rate->point-rate->stored, &consumed,
+				total_in, dst_frames, i == (chans - 1));
+		new_stored = total_in-consumed;
+		memmove(rate->in[i]+rate->point-new_stored,
+				rate->in[i]+rate->point-rate->stored+consumed,
+				new_stored*sizeof(int16_t));
+	}
+	av_resample_compensate(rate->context,
+			total_in-src_frames>filter_size?0:1, src_frames);
+	reinterleave(rate->out, dst, ret, chans);
+	rate->stored = total_in-consumed;
+}
+
+static void pcm_src_close(void *obj)
+{
+	pcm_src_free(obj);
+}
+
+static snd_pcm_rate_ops_t pcm_src_ops = {
+	.close = pcm_src_close,
+	.init = pcm_src_init,
+	.free = pcm_src_free,
+	.reset = pcm_src_reset,
+	.adjust_pitch = pcm_src_adjust_pitch,
+	.convert_s16 = pcm_src_convert_s16,
+	.input_frames = input_frames,
+	.output_frames = output_frames,
+};
+
+int pcm_src_open(unsigned int version, void **objp, snd_pcm_rate_ops_t *ops)
+
+{
+	struct rate_src *rate;
+
+	if (version != SND_PCM_RATE_PLUGIN_VERSION) {
+		fprintf(stderr, "Invalid rate plugin version %x\n", version);
+		return -EINVAL;
+	}
+
+	rate = calloc(1, sizeof(*rate));
+	if (!rate)
+		return -ENOMEM;
+
+	*objp = rate;
+	rate->context = NULL;
+	*ops = pcm_src_ops;
+	return 0;
+}
+
+int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate)(unsigned int version, void **objp,
+			snd_pcm_rate_ops_t *ops)
+{
+	return pcm_src_open(version, objp, ops);
+}
+int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate_higher)(unsigned int version,
+			void **objp, snd_pcm_rate_ops_t *ops)
+{
+	filter_size = 64;
+	return pcm_src_open(version, objp, ops);
+}
+int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate_high)(unsigned int version,
+			void **objp, snd_pcm_rate_ops_t *ops)
+{
+	filter_size = 32;
+	return pcm_src_open(version, objp, ops);
+}
+int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate_fast)(unsigned int version,
+			void **objp, snd_pcm_rate_ops_t *ops)
+{
+	filter_size = 8;
+	return pcm_src_open(version, objp, ops);
+}
+int SND_PCM_RATE_PLUGIN_ENTRY(lavcrate_faster)(unsigned int version,
+			void **objp, snd_pcm_rate_ops_t *ops)
+{
+	filter_size = 4;
+	return pcm_src_open(version, objp, ops);
+}
+
+

[-- Attachment #3: Type: text/plain, Size: 345 bytes --]

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

[-- Attachment #4: Type: text/plain, Size: 161 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Replace libsamplerate resampler with libavcodec
  2007-02-19 19:49     ` Nicholas Kain
@ 2007-02-20 10:56       ` Takashi Iwai
       [not found]         ` <c43861e80702200334l2bcd668ifcbfcce7cc4b75ff@mail.gmail.com>
  0 siblings, 1 reply; 5+ messages in thread
From: Takashi Iwai @ 2007-02-20 10:56 UTC (permalink / raw)
  To: Nicholas Kain; +Cc: alsa-devel

At Mon, 19 Feb 2007 14:49:54 -0500,
Nicholas Kain wrote:
> 
> On 2/19/07, Takashi Iwai <tiwai@suse.de> wrote:
> > IMO, we should _add_ libavcodec resampler plugin instead of replacing
> > the libsamplerate one.  From the license POV, libavcodec is fairly
> > grey, and it's very unlikely bundled in most of linux distributions.
> >
> > So, could you change your patch to add a new subdirectory and plugin?
> > We have already HAVE_AVCODEC conditional in configure script, hence
> > the addition would be pretty simple.
> 
> Sure.  I've attached a patch that places the plugin in a rate-lavc
> subdirectory.  It also provides a minimal .txt document for the plugin as
> well.
> 
> I've also fixed a few minor bugs in the previous patch that were
> preventing optimal quality in conversions, so if anyone has tested the
> patch I sent earlier, it might be worth trying again.

Thanks.  The code looks fine, but I found that you still keep GPL in
rate_lavcrate.c instead of LGPL.  Is it intentional?

Also, please give a changelog description for committing to HG tree,
too.


Takashi

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Replace libsamplerate resampler with libavcodec
       [not found]         ` <c43861e80702200334l2bcd668ifcbfcce7cc4b75ff@mail.gmail.com>
@ 2007-02-20 11:45           ` Takashi Iwai
  0 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2007-02-20 11:45 UTC (permalink / raw)
  To: Nicholas Kain; +Cc: alsa-devel

At Tue, 20 Feb 2007 06:34:45 -0500,
Nicholas Kain wrote:
> 
> On 2/20/07, Takashi Iwai <tiwai@suse.de> wrote:
> > Thanks.  The code looks fine, but I found that you still keep GPL in
> > rate_lavcrate.c instead of LGPL.  Is it intentional?
> 
> Thanks, that was an oversight on my part.  I've changed the license
> text to LGPL and also added a MIT license text to the gcd.h header
> file.
> 
> > Also, please give a changelog description for committing to HG tree,
> > too.
> 
> Changelog:
> 
> Add a new pcm_rate plugin, "lavcrate", that uses the resampling
> filter from libavcodec.  It should provide high performance and
> good output quality.
> Add a documentation file for lavcrate.
> Update autoconf and automake to build lavcrate.

Thanks, now applied to ALSA HG tree.


Takashi

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-02-20 11:45 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20070219060932.GA24147@kain.us>
2007-02-19  6:14 ` [PATCH] Replace libsamplerate resampler with libavcodec Nicholas Kain
2007-02-19 11:12   ` Takashi Iwai
2007-02-19 19:49     ` Nicholas Kain
2007-02-20 10:56       ` Takashi Iwai
     [not found]         ` <c43861e80702200334l2bcd668ifcbfcce7cc4b75ff@mail.gmail.com>
2007-02-20 11:45           ` Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.