Blame pph/rate_speexrate.c

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
}