Blame src/pcm/pcm_rate_linear.c

Packit 4a16fb
/*
Packit 4a16fb
 *  Linear rate converter plugin
Packit 4a16fb
 * 
Packit 4a16fb
 *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
Packit 4a16fb
 *                2004 by Jaroslav Kysela <perex@perex.cz>
Packit 4a16fb
 *                2006 by Takashi Iwai <tiwai@suse.de>
Packit 4a16fb
 *
Packit 4a16fb
 *   This library is free software; you can redistribute it and/or modify
Packit 4a16fb
 *   it under the terms of the GNU Lesser General Public License as
Packit 4a16fb
 *   published by the Free Software Foundation; either version 2.1 of
Packit 4a16fb
 *   the License, or (at your option) any later version.
Packit 4a16fb
 *
Packit 4a16fb
 *   This program is distributed in the hope that it will be useful,
Packit 4a16fb
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a16fb
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 4a16fb
 *   GNU Lesser General Public License for more details.
Packit 4a16fb
 *
Packit 4a16fb
 *   You should have received a copy of the GNU Lesser General Public
Packit 4a16fb
 *   License along with this library; if not, write to the Free Software
Packit 4a16fb
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
#include <inttypes.h>
Packit 4a16fb
#include "bswap.h"
Packit 4a16fb
#include "pcm_local.h"
Packit 4a16fb
#include "pcm_plugin.h"
Packit 4a16fb
#include "pcm_rate.h"
Packit 4a16fb
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/* LINEAR_DIV needs to be large enough to handle resampling from 768000 -> 8000 */
Packit 4a16fb
#define LINEAR_DIV_SHIFT 19
Packit 4a16fb
#define LINEAR_DIV (1<
Packit 4a16fb
Packit 4a16fb
struct rate_linear {
Packit 4a16fb
	unsigned int get_idx;
Packit 4a16fb
	unsigned int put_idx;
Packit 4a16fb
	unsigned int pitch;
Packit 4a16fb
	unsigned int pitch_shift;	/* for expand interpolation */
Packit 4a16fb
	unsigned int channels;
Packit 4a16fb
	int16_t *old_sample;
Packit 4a16fb
	void (*func)(struct rate_linear *rate,
Packit 4a16fb
		     const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
		     snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
Packit 4a16fb
		     const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
		     snd_pcm_uframes_t src_offset, unsigned int src_frames);
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
static snd_pcm_uframes_t input_frames(void *obj, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	struct rate_linear *rate = obj;
Packit 4a16fb
	if (frames == 0)
Packit 4a16fb
		return 0;
Packit 4a16fb
	/* Round toward zero */
Packit 4a16fb
	return muldiv_near(frames, LINEAR_DIV, rate->pitch);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	struct rate_linear *rate = obj;
Packit 4a16fb
	if (frames == 0)
Packit 4a16fb
		return 0;
Packit 4a16fb
	/* Round toward zero */
Packit 4a16fb
	return muldiv_near(frames, rate->pitch, LINEAR_DIV);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void linear_expand(struct rate_linear *rate,
Packit 4a16fb
			  const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
			  snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
Packit 4a16fb
			  const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
			  snd_pcm_uframes_t src_offset, unsigned int src_frames)
Packit 4a16fb
{
Packit 4a16fb
#define GET16_LABELS
Packit 4a16fb
#define PUT16_LABELS
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef GET16_LABELS
Packit 4a16fb
#undef PUT16_LABELS
Packit 4a16fb
	void *get = get16_labels[rate->get_idx];
Packit 4a16fb
	void *put = put16_labels[rate->put_idx];
Packit 4a16fb
	unsigned int get_threshold = rate->pitch;
Packit 4a16fb
	unsigned int channel;
Packit 4a16fb
	unsigned int src_frames1;
Packit 4a16fb
	unsigned int dst_frames1;
Packit 4a16fb
	int16_t sample = 0;
Packit 4a16fb
	unsigned int pos;
Packit 4a16fb
	
Packit 4a16fb
	for (channel = 0; channel < rate->channels; ++channel) {
Packit 4a16fb
		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
Packit 4a16fb
		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
Packit 4a16fb
		const char *src;
Packit 4a16fb
		char *dst;
Packit 4a16fb
		int src_step, dst_step;
Packit 4a16fb
		int16_t old_sample = 0;
Packit 4a16fb
		int16_t new_sample;
Packit 4a16fb
		int old_weight, new_weight;
Packit 4a16fb
		src = snd_pcm_channel_area_addr(src_area, src_offset);
Packit 4a16fb
		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
Packit 4a16fb
		src_step = snd_pcm_channel_area_step(src_area);
Packit 4a16fb
		dst_step = snd_pcm_channel_area_step(dst_area);
Packit 4a16fb
		src_frames1 = 0;
Packit 4a16fb
		dst_frames1 = 0;
Packit 4a16fb
		new_sample = rate->old_sample[channel];
Packit 4a16fb
		pos = get_threshold;
Packit 4a16fb
		while (dst_frames1 < dst_frames) {
Packit 4a16fb
			if (pos >= get_threshold) {
Packit 4a16fb
				pos -= get_threshold;
Packit 4a16fb
				old_sample = new_sample;
Packit 4a16fb
				if (src_frames1 < src_frames) {
Packit 4a16fb
					goto *get;
Packit 4a16fb
#define GET16_END after_get
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef GET16_END
Packit 4a16fb
				after_get:
Packit 4a16fb
					new_sample = sample;
Packit 4a16fb
				}
Packit 4a16fb
			}
Packit 4a16fb
			new_weight = (pos << (16 - rate->pitch_shift)) / (get_threshold >> rate->pitch_shift);
Packit 4a16fb
			old_weight = 0x10000 - new_weight;
Packit 4a16fb
			sample = (old_sample * old_weight + new_sample * new_weight) >> 16;
Packit 4a16fb
			goto *put;
Packit 4a16fb
#define PUT16_END after_put
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef PUT16_END
Packit 4a16fb
		after_put:
Packit 4a16fb
			dst += dst_step;
Packit 4a16fb
			dst_frames1++;
Packit 4a16fb
			pos += LINEAR_DIV;
Packit 4a16fb
			if (pos >= get_threshold) {
Packit 4a16fb
				src += src_step;
Packit 4a16fb
				src_frames1++;
Packit 4a16fb
			}
Packit 4a16fb
		} 
Packit 4a16fb
		rate->old_sample[channel] = new_sample;
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* optimized version for S16 format */
Packit 4a16fb
static void linear_expand_s16(struct rate_linear *rate,
Packit 4a16fb
			      const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
			      snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
Packit 4a16fb
			      const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
			      snd_pcm_uframes_t src_offset, unsigned int src_frames)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int channel;
Packit 4a16fb
	unsigned int src_frames1;
Packit 4a16fb
	unsigned int dst_frames1;
Packit 4a16fb
	unsigned int get_threshold = rate->pitch;
Packit 4a16fb
	unsigned int pos;
Packit 4a16fb
	
Packit 4a16fb
	for (channel = 0; channel < rate->channels; ++channel) {
Packit 4a16fb
		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
Packit 4a16fb
		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
Packit 4a16fb
		const int16_t *src;
Packit 4a16fb
		int16_t *dst;
Packit 4a16fb
		int src_step, dst_step;
Packit 4a16fb
		int16_t old_sample = 0;
Packit 4a16fb
		int16_t new_sample;
Packit 4a16fb
		int old_weight, new_weight;
Packit 4a16fb
		src = snd_pcm_channel_area_addr(src_area, src_offset);
Packit 4a16fb
		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
Packit 4a16fb
		src_step = snd_pcm_channel_area_step(src_area) >> 1;
Packit 4a16fb
		dst_step = snd_pcm_channel_area_step(dst_area) >> 1;
Packit 4a16fb
		src_frames1 = 0;
Packit 4a16fb
		dst_frames1 = 0;
Packit 4a16fb
		new_sample = rate->old_sample[channel];
Packit 4a16fb
		pos = get_threshold;
Packit 4a16fb
		while (dst_frames1 < dst_frames) {
Packit 4a16fb
			if (pos >= get_threshold) {
Packit 4a16fb
				pos -= get_threshold;
Packit 4a16fb
				old_sample = new_sample;
Packit 4a16fb
				if (src_frames1 < src_frames)
Packit 4a16fb
					new_sample = *src;
Packit 4a16fb
			}
Packit 4a16fb
			new_weight = (pos << (16 - rate->pitch_shift)) / (get_threshold >> rate->pitch_shift);
Packit 4a16fb
			old_weight = 0x10000 - new_weight;
Packit 4a16fb
			*dst = (old_sample * old_weight + new_sample * new_weight) >> 16;
Packit 4a16fb
			dst += dst_step;
Packit 4a16fb
			dst_frames1++;
Packit 4a16fb
			pos += LINEAR_DIV;
Packit 4a16fb
			if (pos >= get_threshold) {
Packit 4a16fb
				src += src_step;
Packit 4a16fb
				src_frames1++;
Packit 4a16fb
			}
Packit 4a16fb
		} 
Packit 4a16fb
		rate->old_sample[channel] = new_sample;
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void linear_shrink(struct rate_linear *rate,
Packit 4a16fb
			  const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
			  snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
Packit 4a16fb
			  const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
			  snd_pcm_uframes_t src_offset, unsigned int src_frames)
Packit 4a16fb
{
Packit 4a16fb
#define GET16_LABELS
Packit 4a16fb
#define PUT16_LABELS
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef GET16_LABELS
Packit 4a16fb
#undef PUT16_LABELS
Packit 4a16fb
	void *get = get16_labels[rate->get_idx];
Packit 4a16fb
	void *put = put16_labels[rate->put_idx];
Packit 4a16fb
	unsigned int get_increment = rate->pitch;
Packit 4a16fb
	unsigned int channel;
Packit 4a16fb
	unsigned int src_frames1;
Packit 4a16fb
	unsigned int dst_frames1;
Packit 4a16fb
	int16_t sample = 0;
Packit 4a16fb
	unsigned int pos;
Packit 4a16fb
Packit 4a16fb
	for (channel = 0; channel < rate->channels; ++channel) {
Packit 4a16fb
		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
Packit 4a16fb
		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
Packit 4a16fb
		const char *src;
Packit 4a16fb
		char *dst;
Packit 4a16fb
		int src_step, dst_step;
Packit 4a16fb
		int16_t old_sample = 0;
Packit 4a16fb
		int16_t new_sample = 0;
Packit 4a16fb
		int old_weight, new_weight;
Packit 4a16fb
		pos = LINEAR_DIV - get_increment; /* Force first sample to be copied */
Packit 4a16fb
		src = snd_pcm_channel_area_addr(src_area, src_offset);
Packit 4a16fb
		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
Packit 4a16fb
		src_step = snd_pcm_channel_area_step(src_area);
Packit 4a16fb
		dst_step = snd_pcm_channel_area_step(dst_area);
Packit 4a16fb
		src_frames1 = 0;
Packit 4a16fb
		dst_frames1 = 0;
Packit 4a16fb
		while (src_frames1 < src_frames) {
Packit 4a16fb
			
Packit 4a16fb
			goto *get;
Packit 4a16fb
#define GET16_END after_get
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef GET16_END
Packit 4a16fb
		after_get:
Packit 4a16fb
			new_sample = sample;
Packit 4a16fb
			src += src_step;
Packit 4a16fb
			src_frames1++;
Packit 4a16fb
			pos += get_increment;
Packit 4a16fb
			if (pos >= LINEAR_DIV) {
Packit 4a16fb
				pos -= LINEAR_DIV;
Packit 4a16fb
				old_weight = (pos << (32 - LINEAR_DIV_SHIFT)) / (get_increment >> (LINEAR_DIV_SHIFT - 16));
Packit 4a16fb
				new_weight = 0x10000 - old_weight;
Packit 4a16fb
				sample = (old_sample * old_weight + new_sample * new_weight) >> 16;
Packit 4a16fb
				goto *put;
Packit 4a16fb
#define PUT16_END after_put
Packit 4a16fb
#include "plugin_ops.h"
Packit 4a16fb
#undef PUT16_END
Packit 4a16fb
			after_put:
Packit 4a16fb
				dst += dst_step;
Packit 4a16fb
				dst_frames1++;
Packit 4a16fb
				if (CHECK_SANITY(dst_frames1 > dst_frames)) {
Packit 4a16fb
					SNDERR("dst_frames overflow");
Packit 4a16fb
					break;
Packit 4a16fb
				}
Packit 4a16fb
			}
Packit 4a16fb
			old_sample = new_sample;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* optimized version for S16 format */
Packit 4a16fb
static void linear_shrink_s16(struct rate_linear *rate,
Packit 4a16fb
			      const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
			      snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
Packit 4a16fb
			      const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
			      snd_pcm_uframes_t src_offset, unsigned int src_frames)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int get_increment = rate->pitch;
Packit 4a16fb
	unsigned int channel;
Packit 4a16fb
	unsigned int src_frames1;
Packit 4a16fb
	unsigned int dst_frames1;
Packit 4a16fb
	unsigned int pos = 0;
Packit 4a16fb
Packit 4a16fb
	for (channel = 0; channel < rate->channels; ++channel) {
Packit 4a16fb
		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
Packit 4a16fb
		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
Packit 4a16fb
		const int16_t *src;
Packit 4a16fb
		int16_t *dst;
Packit 4a16fb
		int src_step, dst_step;
Packit 4a16fb
		int16_t old_sample = 0;
Packit 4a16fb
		int16_t new_sample = 0;
Packit 4a16fb
		int old_weight, new_weight;
Packit 4a16fb
		pos = LINEAR_DIV - get_increment; /* Force first sample to be copied */
Packit 4a16fb
		src = snd_pcm_channel_area_addr(src_area, src_offset);
Packit 4a16fb
		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
Packit 4a16fb
		src_step = snd_pcm_channel_area_step(src_area) >> 1;
Packit 4a16fb
		dst_step = snd_pcm_channel_area_step(dst_area) >> 1 ;
Packit 4a16fb
		src_frames1 = 0;
Packit 4a16fb
		dst_frames1 = 0;
Packit 4a16fb
		while (src_frames1 < src_frames) {
Packit 4a16fb
			
Packit 4a16fb
			new_sample = *src;
Packit 4a16fb
			src += src_step;
Packit 4a16fb
			src_frames1++;
Packit 4a16fb
			pos += get_increment;
Packit 4a16fb
			if (pos >= LINEAR_DIV) {
Packit 4a16fb
				pos -= LINEAR_DIV;
Packit 4a16fb
				old_weight = (pos << (32 - LINEAR_DIV_SHIFT)) / (get_increment >> (LINEAR_DIV_SHIFT - 16));
Packit 4a16fb
				new_weight = 0x10000 - old_weight;
Packit 4a16fb
				*dst = (old_sample * old_weight + new_sample * new_weight) >> 16;
Packit 4a16fb
				dst += dst_step;
Packit 4a16fb
				dst_frames1++;
Packit 4a16fb
				if (CHECK_SANITY(dst_frames1 > dst_frames)) {
Packit 4a16fb
					SNDERR("dst_frames overflow");
Packit 4a16fb
					break;
Packit 4a16fb
				}
Packit 4a16fb
			}
Packit 4a16fb
			old_sample = new_sample;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void linear_convert(void *obj, 
Packit 4a16fb
			   const snd_pcm_channel_area_t *dst_areas,
Packit 4a16fb
			   snd_pcm_uframes_t dst_offset, unsigned int dst_frames,
Packit 4a16fb
			   const snd_pcm_channel_area_t *src_areas,
Packit 4a16fb
			   snd_pcm_uframes_t src_offset, unsigned int src_frames)
Packit 4a16fb
{
Packit 4a16fb
	struct rate_linear *rate = obj;
Packit 4a16fb
	rate->func(rate, dst_areas, dst_offset, dst_frames,
Packit 4a16fb
		   src_areas, src_offset, src_frames);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void linear_free(void *obj)
Packit 4a16fb
{
Packit 4a16fb
	struct rate_linear *rate = obj;
Packit 4a16fb
Packit 4a16fb
	free(rate->old_sample);
Packit 4a16fb
	rate->old_sample = NULL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int linear_init(void *obj, snd_pcm_rate_info_t *info)
Packit 4a16fb
{
Packit 4a16fb
	struct rate_linear *rate = obj;
Packit 4a16fb
Packit 4a16fb
	rate->get_idx = snd_pcm_linear_get_index(info->in.format, SND_PCM_FORMAT_S16);
Packit 4a16fb
	rate->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, info->out.format);
Packit 4a16fb
	if (info->in.rate < info->out.rate) {
Packit 4a16fb
		if (info->in.format == info->out.format && info->in.format == SND_PCM_FORMAT_S16)
Packit 4a16fb
			rate->func = linear_expand_s16;
Packit 4a16fb
		else
Packit 4a16fb
			rate->func = linear_expand;
Packit 4a16fb
		/* pitch is get_threshold */
Packit 4a16fb
	} else {
Packit 4a16fb
		if (info->in.format == info->out.format && info->in.format == SND_PCM_FORMAT_S16)
Packit 4a16fb
			rate->func = linear_shrink_s16;
Packit 4a16fb
		else
Packit 4a16fb
			rate->func = linear_shrink;
Packit 4a16fb
		/* pitch is get_increment */
Packit 4a16fb
	}
Packit 4a16fb
	rate->pitch = (((uint64_t)info->out.rate * LINEAR_DIV) +
Packit 4a16fb
		       (info->in.rate / 2)) / info->in.rate;
Packit 4a16fb
	rate->channels = info->channels;
Packit 4a16fb
Packit 4a16fb
	free(rate->old_sample);
Packit 4a16fb
	rate->old_sample = malloc(sizeof(*rate->old_sample) * rate->channels);
Packit 4a16fb
	if (! rate->old_sample)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int linear_adjust_pitch(void *obj, snd_pcm_rate_info_t *info)
Packit 4a16fb
{
Packit 4a16fb
	struct rate_linear *rate = obj;
Packit 4a16fb
	snd_pcm_uframes_t cframes;
Packit 4a16fb
Packit 4a16fb
	rate->pitch = (((uint64_t)info->out.period_size * LINEAR_DIV) +
Packit 4a16fb
		       (info->in.period_size/2) ) / info->in.period_size;
Packit 4a16fb
			
Packit 4a16fb
	cframes = input_frames(rate, info->out.period_size);
Packit 4a16fb
	while (cframes != info->in.period_size) {
Packit 4a16fb
		snd_pcm_uframes_t cframes_new;
Packit 4a16fb
		if (cframes > info->in.period_size)
Packit 4a16fb
			rate->pitch++;
Packit 4a16fb
		else
Packit 4a16fb
			rate->pitch--;
Packit 4a16fb
		cframes_new = input_frames(rate, info->out.period_size);
Packit 4a16fb
		if ((cframes > info->in.period_size && cframes_new < info->in.period_size) ||
Packit 4a16fb
		    (cframes < info->in.period_size && cframes_new > info->in.period_size)) {
Packit 4a16fb
			SNDERR("invalid pcm period_size %ld -> %ld",
Packit 4a16fb
			       info->in.period_size, info->out.period_size);
Packit 4a16fb
			return -EIO;
Packit 4a16fb
		}
Packit 4a16fb
		cframes = cframes_new;
Packit 4a16fb
	}
Packit 4a16fb
	if (rate->pitch >= LINEAR_DIV) {
Packit 4a16fb
		/* shift for expand linear interpolation */
Packit 4a16fb
		rate->pitch_shift = 0;
Packit 4a16fb
		while ((rate->pitch >> rate->pitch_shift) >= (1 << 16))
Packit 4a16fb
			rate->pitch_shift++;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void linear_reset(void *obj)
Packit 4a16fb
{
Packit 4a16fb
	struct rate_linear *rate = obj;
Packit 4a16fb
Packit 4a16fb
	/* for expand */
Packit 4a16fb
	if (rate->old_sample)
Packit 4a16fb
		memset(rate->old_sample, 0, sizeof(*rate->old_sample) * rate->channels);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void linear_close(void *obj)
Packit 4a16fb
{
Packit 4a16fb
	free(obj);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int get_supported_rates(ATTRIBUTE_UNUSED void *rate,
Packit 4a16fb
			       unsigned int *rate_min, unsigned int *rate_max)
Packit 4a16fb
{
Packit 4a16fb
	*rate_min = SND_PCM_PLUGIN_RATE_MIN;
Packit 4a16fb
	*rate_max = SND_PCM_PLUGIN_RATE_MAX;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void linear_dump(ATTRIBUTE_UNUSED void *rate, snd_output_t *out)
Packit 4a16fb
{
Packit 4a16fb
	snd_output_printf(out, "Converter: linear-interpolation\n");
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_rate_ops_t linear_ops = {
Packit 4a16fb
	.close = linear_close,
Packit 4a16fb
	.init = linear_init,
Packit 4a16fb
	.free = linear_free,
Packit 4a16fb
	.reset = linear_reset,
Packit 4a16fb
	.adjust_pitch = linear_adjust_pitch,
Packit 4a16fb
	.convert = linear_convert,
Packit 4a16fb
	.input_frames = input_frames,
Packit 4a16fb
	.output_frames = output_frames,
Packit 4a16fb
	.version = SND_PCM_RATE_PLUGIN_VERSION,
Packit 4a16fb
	.get_supported_rates = get_supported_rates,
Packit 4a16fb
	.dump = linear_dump,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
int SND_PCM_RATE_PLUGIN_ENTRY(linear) (ATTRIBUTE_UNUSED unsigned int version,
Packit 4a16fb
				       void **objp, snd_pcm_rate_ops_t *ops)
Packit 4a16fb
{
Packit 4a16fb
	struct rate_linear *rate;
Packit 4a16fb
Packit 4a16fb
	rate = calloc(1, sizeof(*rate));
Packit 4a16fb
	if (! rate)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	*objp = rate;
Packit 4a16fb
	*ops = linear_ops;
Packit 4a16fb
	return 0;
Packit 4a16fb
}