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