|
Packit |
675970 |
/* Rate converter plugin using Public Parrot Hack
|
|
Packit |
675970 |
Copyright (C) 2007 Jean-Marc Valin
|
|
Packit |
675970 |
|
|
Packit |
675970 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
675970 |
modification, are permitted provided that the following conditions are
|
|
Packit |
675970 |
met:
|
|
Packit |
675970 |
|
|
Packit |
675970 |
1. Redistributions of source code must retain the above copyright notice,
|
|
Packit |
675970 |
this list of conditions and the following disclaimer.
|
|
Packit |
675970 |
|
|
Packit |
675970 |
2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
675970 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
675970 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
675970 |
|
|
Packit |
675970 |
3. The name of the author may not be used to endorse or promote products
|
|
Packit |
675970 |
derived from this software without specific prior written permission.
|
|
Packit |
675970 |
|
|
Packit |
675970 |
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
Packit |
675970 |
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
Packit |
675970 |
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
Packit |
675970 |
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
Packit |
675970 |
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
Packit |
675970 |
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit |
675970 |
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit |
675970 |
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
Packit |
675970 |
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
Packit |
675970 |
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit |
675970 |
POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
675970 |
*/
|
|
Packit |
675970 |
|
|
Packit |
675970 |
#include "config.h"
|
|
Packit |
675970 |
#include <stdio.h>
|
|
Packit |
675970 |
#include <alsa/asoundlib.h>
|
|
Packit |
675970 |
#include <alsa/pcm_rate.h>
|
|
Packit |
675970 |
|
|
Packit |
675970 |
#ifdef USE_LIBSPEEX
|
|
Packit |
675970 |
#include <speex/speex_resampler.h>
|
|
Packit |
675970 |
#else
|
|
Packit |
675970 |
#include "speex_resampler.h"
|
|
Packit |
675970 |
#endif
|
|
Packit |
675970 |
|
|
Packit |
675970 |
struct rate_src {
|
|
Packit |
675970 |
int quality;
|
|
Packit |
675970 |
unsigned int channels;
|
|
Packit |
675970 |
SpeexResamplerState *st;
|
|
Packit |
675970 |
};
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static snd_pcm_uframes_t input_frames(void *obj, snd_pcm_uframes_t frames)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
spx_uint32_t num, den;
|
|
Packit |
675970 |
struct rate_src *rate = obj;
|
|
Packit |
675970 |
if (frames == 0)
|
|
Packit |
675970 |
return 0;
|
|
Packit |
675970 |
speex_resampler_get_ratio(rate->st, &num, &den;;
|
|
Packit |
675970 |
return (snd_pcm_uframes_t)((frames*num+(den>>1))/den);
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
spx_uint32_t num, den;
|
|
Packit |
675970 |
struct rate_src *rate = obj;
|
|
Packit |
675970 |
if (frames == 0)
|
|
Packit |
675970 |
return 0;
|
|
Packit |
675970 |
speex_resampler_get_ratio(rate->st, &num, &den;;
|
|
Packit |
675970 |
return (snd_pcm_uframes_t)((frames*den+(num>>1))/num);
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static void pcm_src_free(void *obj)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
struct rate_src *rate = obj;
|
|
Packit |
675970 |
if (rate->st)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
speex_resampler_destroy(rate->st);
|
|
Packit |
675970 |
rate->st = NULL;
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
struct rate_src *rate = obj;
|
|
Packit |
675970 |
int err;
|
|
Packit |
675970 |
|
|
Packit |
675970 |
if (! rate->st || rate->channels != info->channels) {
|
|
Packit |
675970 |
if (rate->st)
|
|
Packit |
675970 |
speex_resampler_destroy(rate->st);
|
|
Packit |
675970 |
rate->channels = info->channels;
|
|
Packit |
675970 |
rate->st = speex_resampler_init_frac(rate->channels, info->in.period_size, info->out.period_size, info->in.rate, info->out.rate, rate->quality, &err;;
|
|
Packit |
675970 |
if (! rate->st)
|
|
Packit |
675970 |
return -EINVAL;
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
return 0;
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
struct rate_src *rate = obj;
|
|
Packit |
675970 |
speex_resampler_set_rate_frac(rate->st, info->in.period_size, info->out.period_size, info->in.rate, info->out.rate);
|
|
Packit |
675970 |
return 0;
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static void pcm_src_reset(void *obj)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
struct rate_src *rate = obj;
|
|
Packit |
675970 |
speex_resampler_reset_mem(rate->st);
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int dst_frames,
|
|
Packit |
675970 |
const int16_t *src, unsigned int src_frames)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
struct rate_src *rate = obj;
|
|
Packit |
675970 |
speex_resampler_process_interleaved_int(rate->st, src, &src_frames, dst, &dst_frames);
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static void pcm_src_close(void *obj)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
free(obj);
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
Packit |
675970 |
static int get_supported_rates(void *obj, unsigned int *rate_min,
|
|
Packit |
675970 |
unsigned int *rate_max)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
*rate_min = *rate_max = 0; /* both unlimited */
|
|
Packit |
675970 |
return 0;
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static void dump(void *obj, snd_output_t *out)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
snd_output_printf(out, "Converter: libspeex "
|
|
Packit |
675970 |
#ifdef USE_LIBSPEEX
|
|
Packit |
675970 |
"(external)"
|
|
Packit |
675970 |
#else
|
|
Packit |
675970 |
"(builtin)"
|
|
Packit |
675970 |
#endif
|
|
Packit |
675970 |
"\n");
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
#endif
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static snd_pcm_rate_ops_t pcm_src_ops = {
|
|
Packit |
675970 |
.close = pcm_src_close,
|
|
Packit |
675970 |
.init = pcm_src_init,
|
|
Packit |
675970 |
.free = pcm_src_free,
|
|
Packit |
675970 |
.reset = pcm_src_reset,
|
|
Packit |
675970 |
.adjust_pitch = pcm_src_adjust_pitch,
|
|
Packit |
675970 |
.convert_s16 = pcm_src_convert_s16,
|
|
Packit |
675970 |
.input_frames = input_frames,
|
|
Packit |
675970 |
.output_frames = output_frames,
|
|
Packit |
675970 |
#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
Packit |
675970 |
.version = SND_PCM_RATE_PLUGIN_VERSION,
|
|
Packit |
675970 |
.get_supported_rates = get_supported_rates,
|
|
Packit |
675970 |
.dump = dump,
|
|
Packit |
675970 |
#endif
|
|
Packit |
675970 |
};
|
|
Packit |
675970 |
|
|
Packit |
675970 |
static int pcm_src_open(unsigned int version, void **objp,
|
|
Packit |
675970 |
snd_pcm_rate_ops_t *ops, int quality)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
struct rate_src *rate;
|
|
Packit |
675970 |
|
|
Packit |
675970 |
#if SND_PCM_RATE_PLUGIN_VERSION < 0x010002
|
|
Packit |
675970 |
if (version != SND_PCM_RATE_PLUGIN_VERSION) {
|
|
Packit |
675970 |
fprintf(stderr, "Invalid rate plugin version %x\n", version);
|
|
Packit |
675970 |
return -EINVAL;
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
#endif
|
|
Packit |
675970 |
rate = calloc(1, sizeof(*rate));
|
|
Packit |
675970 |
if (! rate)
|
|
Packit |
675970 |
return -ENOMEM;
|
|
Packit |
675970 |
rate->quality = quality;
|
|
Packit |
675970 |
|
|
Packit |
675970 |
*objp = rate;
|
|
Packit |
675970 |
#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002
|
|
Packit |
675970 |
if (version == 0x010001)
|
|
Packit |
675970 |
memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t));
|
|
Packit |
675970 |
else
|
|
Packit |
675970 |
#endif
|
|
Packit |
675970 |
*ops = pcm_src_ops;
|
|
Packit |
675970 |
return 0;
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
int SND_PCM_RATE_PLUGIN_ENTRY(speexrate) (unsigned int version, void **objp,
|
|
Packit |
675970 |
snd_pcm_rate_ops_t *ops)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
return pcm_src_open(version, objp, ops, 3);
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
int SND_PCM_RATE_PLUGIN_ENTRY(speexrate_best) (unsigned int version, void **objp,
|
|
Packit |
675970 |
snd_pcm_rate_ops_t *ops)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
return pcm_src_open(version, objp, ops, 10);
|
|
Packit |
675970 |
}
|
|
Packit |
675970 |
|
|
Packit |
675970 |
int SND_PCM_RATE_PLUGIN_ENTRY(speexrate_medium) (unsigned int version, void **objp,
|
|
Packit |
675970 |
snd_pcm_rate_ops_t *ops)
|
|
Packit |
675970 |
{
|
|
Packit |
675970 |
return pcm_src_open(version, objp, ops, 5);
|
|
Packit |
675970 |
}
|