diff options
author | Takashi Iwai <tiwai@suse.de> | 2006-04-06 17:37:13 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2006-04-06 17:37:13 +0200 |
commit | 74bdac50b257b986cea38a2c08134c430fc5654f (patch) | |
tree | 5e30207026f4f777edb21f6bd729087f5e0a3c4c /rate | |
parent | 423a6f3c7be331984ec74587bf278204d19a4467 (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.am | 19 | ||||
-rw-r--r-- | rate/rate_samplerate.c | 193 |
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); +} |