Blame pph/rate_speexrate.c

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