summaryrefslogtreecommitdiffstats
path: root/rate
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2006-04-06 17:37:13 +0200
committerTakashi Iwai <tiwai@suse.de>2006-04-06 17:37:13 +0200
commit74bdac50b257b986cea38a2c08134c430fc5654f (patch)
tree5e30207026f4f777edb21f6bd729087f5e0a3c4c /rate
parent423a6f3c7be331984ec74587bf278204d19a4467 (diff)
Add samplerate rate converter plugin
Added a rate converter pluging using libsamplerate. The plugin is built only when libsamplerate is detected by configure. See doc/samplerate.txt for usage. This plugin is released under GPL (to follow the license of libsamplerate), not LGPL.
Diffstat (limited to 'rate')
-rw-r--r--rate/Makefile.am19
-rw-r--r--rate/rate_samplerate.c193
2 files changed, 212 insertions, 0 deletions
diff --git a/rate/Makefile.am b/rate/Makefile.am
new file mode 100644
index 0000000..7b63f02
--- /dev/null
+++ b/rate/Makefile.am
@@ -0,0 +1,19 @@
+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_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@
+
+install-exec-hook:
+ rm -f $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_samplerate_*.so
+ $(LN_S) libasound_module_rate_samplerate.so $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_samplerate_best.so
+ $(LN_S) libasound_module_rate_samplerate.so $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_samplerate_medium.so
+ $(LN_S) libasound_module_rate_samplerate.so $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_samplerate_order.so
+ $(LN_S) libasound_module_rate_samplerate.so $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_samplerate_linear.so
+
+uninstall-hook:
+ rm -f $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_samplerate_*.so
diff --git a/rate/rate_samplerate.c b/rate/rate_samplerate.c
new file mode 100644
index 0000000..af5c9c0
--- /dev/null
+++ b/rate/rate_samplerate.c
@@ -0,0 +1,193 @@
+/*
+ * Rate converter plugin using 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 <samplerate.h>
+#include <alsa/asoundlib.h>
+#include <alsa/pcm_rate.h>
+
+struct rate_src {
+ double ratio;
+ int converter;
+ 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);
+}
+
+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);
+}
+
+static void pcm_src_free(void *obj)
+{
+ struct rate_src *rate = obj;
+
+ 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;
+ }
+}
+
+static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info)
+{
+ struct rate_src *rate = obj;
+ int err;
+
+ if (! rate->state || rate->channels != info->channels) {
+ if (rate->state)
+ src_delete(rate->state);
+ rate->channels = info->channels;
+ rate->state = src_new(rate->converter, rate->channels, &err);
+ if (! rate->state)
+ 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) {
+ 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;
+}
+
+static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info)
+{
+ struct rate_src *rate = obj;
+
+ rate->ratio = ((double)info->out.period_size / (double)info->in.period_size);
+ rate->data.src_ratio = rate->ratio;
+ return 0;
+}
+
+static void pcm_src_reset(void *obj)
+{
+ struct rate_src *rate = obj;
+
+ src_reset(rate->state);
+}
+
+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;
+
+ 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);
+}
+
+static void pcm_src_close(void *obj)
+{
+ 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,
+};
+
+static int pcm_src_open(unsigned int version, void **objp,
+ snd_pcm_rate_ops_t *ops, int type)
+{
+ 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;
+ rate->converter = type;
+
+ *objp = rate;
+ *ops = pcm_src_ops;
+ return 0;
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}