linear_resampler.c revision 8ddfd645c98089cf6631bef2c4cb79daa92b2757
18ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao/* Copyright (c) 2014 The Chromium OS Author. All rights reserved.
28ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao * Use of this source code is governed by a BSD-style license that can be
38ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao * found in the LICENSE file.
48ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao */
58ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
68ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao#include "cras_audio_area.h"
78ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao#include "linear_resampler.h"
88ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
98ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao/* A linear resampler.
108ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao * Members:
118ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao *    num_channels - The number of channles in once frames.
128ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao *    format_bytes - The size of one frame in bytes.
138ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao *    src_offset - The accumulated offset for resampled src data.
148ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao *    dst_offset - The accumulated offset for resampled dst data.
158ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao *    src_rate - The source sample rate.
168ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao *    dst_rate - The destination sample rate.
178ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao */
188ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chaostruct linear_resampler {
198ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	unsigned int num_channels;
208ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	unsigned int format_bytes;
218ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	unsigned int src_offset;
228ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	unsigned int dst_offset;
238ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	unsigned int src_rate;
248ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	unsigned int dst_rate;
258ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	float f;
268ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao};
278ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
288ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chaostruct linear_resampler *linear_resampler_create(unsigned int num_channels,
298ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao					     unsigned int format_bytes,
308ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao					     unsigned int src_rate,
318ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao					     unsigned int dst_rate)
328ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao{
338ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	struct linear_resampler *lr;
348ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
358ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr = (struct linear_resampler *)calloc(1, sizeof(*lr));
368ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->num_channels = num_channels;
378ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->format_bytes = format_bytes;
388ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
398ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->src_rate = src_rate;
408ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->dst_rate = dst_rate;
418ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->f = (float)dst_rate / src_rate;
428ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
438ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	return lr;
448ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao}
458ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
468ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chaovoid linear_resampler_destroy(struct linear_resampler *lr)
478ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao{
488ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	if (lr)
498ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		free(lr);
508ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao}
518ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
528ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chaovoid linear_resampler_set_rates(struct linear_resampler *lr,
538ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			      unsigned int from,
548ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			      unsigned int to)
558ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao{
568ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->src_rate = from;
578ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->dst_rate = to;
588ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->f = (float)to / from;
598ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->src_offset = 0;
608ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->dst_offset = 0;
618ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao}
628ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
638ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chaounsigned int linear_resampler_resample(struct linear_resampler *lr,
648ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			     uint8_t *src,
658ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			     unsigned int *src_frames,
668ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			     uint8_t *dst,
678ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			     unsigned dst_frames)
688ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao{
698ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	int ch;
708ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	unsigned int src_idx = 0;
718ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	unsigned int dst_idx = 0;
728ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	float src_pos;
738ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	int16_t *in, *out;
748ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
758ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	for (dst_idx = 0; dst_idx <= dst_frames; dst_idx++) {
768ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
778ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		src_pos = (float)(lr->dst_offset + dst_idx) / lr->f;
788ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		if (src_pos > lr->src_offset)
798ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			src_pos -= lr->src_offset;
808ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		else
818ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			src_pos = 0;
828ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		src_idx = (unsigned int)src_pos;
838ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
848ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		if (src_pos > *src_frames - 1 || dst_idx >= dst_frames) {
858ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			if (src_pos > *src_frames - 1)
868ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao				src_idx = *src_frames - 1;
878ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			break;
888ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		}
898ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
908ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		in = (int16_t *)(src + src_idx * lr->format_bytes);
918ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		out = (int16_t *)(dst + dst_idx * lr->format_bytes);
928ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
938ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		for (ch = 0; ch < lr->num_channels; ch++) {
948ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao			out[ch] = in[ch] + (src_pos - src_idx) *
958ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao					(in[lr->num_channels + ch] - in[ch]);
968ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		}
978ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	}
988ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
998ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	*src_frames = src_idx + 1;
1008ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
1018ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->src_offset += *src_frames;
1028ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	lr->dst_offset += dst_idx;
1038ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	while ((lr->src_offset > lr->src_rate) &&
1048ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	       (lr->dst_offset > lr->dst_rate)) {
1058ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		lr->src_offset -= lr->src_rate;
1068ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao		lr->dst_offset -= lr->dst_rate;
1078ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	}
1088ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao
1098ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao	return dst_idx;
1108ddfd645c98089cf6631bef2c4cb79daa92b2757Hsin-Yu Chao}
111