1 /* Copyright (c) 2014 The Chromium OS Author. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include "cras_audio_area.h" 7 #include "cras_util.h" 8 #include "linear_resampler.h" 9 10 /* A linear resampler. 11 * Members: 12 * num_channels - The number of channles in once frames. 13 * format_bytes - The size of one frame in bytes. 14 * src_offset - The accumulated offset for resampled src data. 15 * dst_offset - The accumulated offset for resampled dst data. 16 * to_times_100 - The numerator of the rate factor used for SRC. 17 * from_times_100 - The denominator of the rate factor used for SRC. 18 * f - The rate factor used for linear resample. 19 */ 20 struct linear_resampler { 21 unsigned int num_channels; 22 unsigned int format_bytes; 23 unsigned int src_offset; 24 unsigned int dst_offset; 25 unsigned int to_times_100; 26 unsigned int from_times_100; 27 float f; 28 }; 29 30 struct linear_resampler *linear_resampler_create(unsigned int num_channels, 31 unsigned int format_bytes, 32 float src_rate, 33 float dst_rate) 34 { 35 struct linear_resampler *lr; 36 37 lr = (struct linear_resampler *)calloc(1, sizeof(*lr)); 38 if (!lr) 39 return NULL; 40 lr->num_channels = num_channels; 41 lr->format_bytes = format_bytes; 42 43 linear_resampler_set_rates(lr, src_rate, dst_rate); 44 45 return lr; 46 } 47 48 void linear_resampler_destroy(struct linear_resampler *lr) 49 { 50 if (lr) 51 free(lr); 52 } 53 54 void linear_resampler_set_rates(struct linear_resampler *lr, 55 float from, float to) 56 { 57 lr->f = (float)to / from; 58 lr->to_times_100 = to * 100; 59 lr->from_times_100 = from * 100; 60 lr->src_offset = 0; 61 lr->dst_offset = 0; 62 } 63 64 /* Assuming the linear resampler transforms X frames of input buffer into 65 * Y frames of output buffer. The resample method requires the last output 66 * buffer at Y-1 be interpolated from input buffer in range (X-d, X-1) as 67 * illustrated. 68 * Input Index: ... X-1 <--floor--| X 69 * Output Index: ... Y-1 |--ceiling-> Y 70 * 71 * That said, the calculation between input and output frames is based on 72 * equations X-1 = floor(Y/f) and Y = ceil((X-1)*f). Note that in any case 73 * when the resampled frames number isn't sufficient to consume the first 74 * buffer at input or output offset(index 0), always count as one buffer 75 * used so the intput/output offset can always increment. 76 */ 77 unsigned int linear_resampler_out_frames_to_in(struct linear_resampler *lr, 78 unsigned int frames) 79 { 80 float in_frames; 81 if (frames == 0) 82 return 0; 83 84 in_frames = (float)(lr->dst_offset + frames) / lr->f; 85 if ((in_frames > lr->src_offset)) 86 return 1 + (unsigned int)(in_frames - lr->src_offset); 87 else 88 return 1; 89 } 90 91 unsigned int linear_resampler_in_frames_to_out(struct linear_resampler *lr, 92 unsigned int frames) 93 { 94 float out_frames; 95 if (frames == 0) 96 return 0; 97 98 out_frames = lr->f * (lr->src_offset + frames - 1); 99 if (out_frames > lr->dst_offset) 100 return 1 + (unsigned int)(out_frames - lr->dst_offset); 101 else 102 return 1; 103 } 104 105 int linear_resampler_needed(struct linear_resampler *lr) 106 { 107 return lr->from_times_100 != lr->to_times_100; 108 } 109 110 unsigned int linear_resampler_resample(struct linear_resampler *lr, 111 uint8_t *src, 112 unsigned int *src_frames, 113 uint8_t *dst, 114 unsigned dst_frames) 115 { 116 int ch; 117 unsigned int src_idx = 0; 118 unsigned int dst_idx = 0; 119 float src_pos; 120 int16_t *in, *out; 121 122 /* Check for corner cases so that we can assume both src_idx and 123 * dst_idx are valid with value 0 in the loop below. */ 124 if (dst_frames == 0 || *src_frames == 0) { 125 *src_frames = 0; 126 return 0; 127 } 128 129 for (dst_idx = 0; dst_idx <= dst_frames; dst_idx++) { 130 src_pos = (float)(lr->dst_offset + dst_idx) / lr->f; 131 if (src_pos > lr->src_offset) 132 src_pos -= lr->src_offset; 133 else 134 src_pos = 0; 135 src_idx = (unsigned int)src_pos; 136 137 if (src_pos > *src_frames - 1 || dst_idx >= dst_frames) { 138 if (src_pos > *src_frames - 1) 139 src_idx = *src_frames - 1; 140 /* When this loop stops, dst_idx is always at the last 141 * used index incremented by 1. */ 142 break; 143 } 144 145 in = (int16_t *)(src + src_idx * lr->format_bytes); 146 out = (int16_t *)(dst + dst_idx * lr->format_bytes); 147 148 /* Don't do linear interpolcation if src_pos falls on the 149 * last index. */ 150 if (src_idx == *src_frames - 1) { 151 for (ch = 0; ch < lr->num_channels; ch++) 152 out[ch] = in[ch]; 153 } else { 154 for (ch = 0; ch < lr->num_channels; ch++) { 155 out[ch] = in[ch] + (src_pos - src_idx) * 156 (in[lr->num_channels + ch] - in[ch]); 157 } 158 } 159 160 } 161 162 *src_frames = src_idx + 1; 163 164 lr->src_offset += *src_frames; 165 lr->dst_offset += dst_idx; 166 while ((lr->src_offset > lr->from_times_100) && 167 (lr->dst_offset > lr->to_times_100)) { 168 lr->src_offset -= lr->from_times_100; 169 lr->dst_offset -= lr->to_times_100; 170 } 171 172 return dst_idx; 173 } 174