• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
linear_resampler_create(unsigned int num_channels,unsigned int format_bytes,float src_rate,float dst_rate)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 
linear_resampler_destroy(struct linear_resampler * lr)48 void linear_resampler_destroy(struct linear_resampler *lr)
49 {
50 	if (lr)
51 		free(lr);
52 }
53 
linear_resampler_set_rates(struct linear_resampler * lr,float from,float to)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  */
linear_resampler_out_frames_to_in(struct linear_resampler * lr,unsigned int frames)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 
linear_resampler_in_frames_to_out(struct linear_resampler * lr,unsigned int frames)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 
linear_resampler_needed(struct linear_resampler * lr)105 int linear_resampler_needed(struct linear_resampler *lr)
106 {
107 	return lr->from_times_100 != lr->to_times_100;
108 }
109 
linear_resampler_resample(struct linear_resampler * lr,uint8_t * src,unsigned int * src_frames,uint8_t * dst,unsigned dst_frames)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