Trivial resampler fixes
[disorder] / lib / resample.c
1 /*
2 * This file is part of DisOrder.
3 * Copyright (C) 2009 Richard Kettlewell
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /** @file lib/resample.c
20 * @brief Audio resampling
21 *
22 * General purpose audio format conversion. Rate conversion only works if the
23 * SRC samplerate library is available, but the bitness/channel/endianness
24 * conversion works regardless.
25 */
26
27 #include "common.h"
28 #include "resample.h"
29 #include "log.h"
30 #include "mem.h"
31
32 /** @brief Number of intermediate-format samples */
33 #define SAMPLES 1024
34
35 /** @brief Multiplier for signed formats to allow easy switching */
36 #define SIGNED 4
37
38 /** @brief Initialize a resampler
39 * @param rs Resampler
40 * @param input_bits Bits/sample in input
41 * @param input_channels Number of input channels
42 * @param input_signed Whether input samples are signed or unsigned
43 * @param input_rate Frames/second in input
44 * @param output_bits Bits/sample in output
45 * @param output_channels Number of output channels
46 * @param output_rate Frames/second in output
47 * @param output_signed Whether output samples are signed or unsigned
48 *
49 * For formats with more than two channels it's assume that the first
50 * two channels are left and right. No particular meaning is attached
51 * to additional channels other than to assume channel N in an input
52 * means the same as channel N in an output, for N>1.
53 */
54 void resample_init(struct resampler *rs,
55 int input_bits, int input_channels,
56 int input_rate, int input_signed,
57 int input_endian,
58 int output_bits, int output_channels,
59 int output_rate, int output_signed,
60 int output_endian) {
61 int error_;
62 memset(rs, 0, sizeof *rs);
63 assert(input_bits == 8 || input_bits == 16);
64 assert(output_bits == 8 || output_bits == 16);
65 assert(input_endian == ENDIAN_BIG || input_endian == ENDIAN_LITTLE);
66 assert(output_endian == ENDIAN_BIG || output_endian == ENDIAN_LITTLE);
67 assert(ENDIAN_BIG >= 0 && ENDIAN_BIG < SIGNED);
68 assert(ENDIAN_LITTLE >= 0 && ENDIAN_LITTLE < SIGNED);
69 rs->input_bits = input_bits;
70 rs->input_channels = input_channels;
71 rs->input_rate = input_rate;
72 rs->input_signed = SIGNED * !!input_signed;
73 rs->input_endian = input_endian;
74 rs->output_bits = output_bits;
75 rs->output_channels = output_channels;
76 rs->output_rate = output_rate;
77 rs->output_signed = SIGNED * !!output_signed;
78 rs->output_endian = output_endian;
79 rs->input_bytes_per_sample = (rs->input_bits + 7) / 8;
80 rs->input_bytes_per_frame = rs->input_channels * rs->input_bytes_per_sample;
81 if(rs->input_rate != rs->output_rate) {
82 #if HAVE_SAMPLERATE_H
83 rs->state = src_new(SRC_SINC_BEST_QUALITY, rs->output_channels, &error_);
84 if(!rs->state)
85 fatal(0, "calling src_new: %s", src_strerror(error_));
86 #else
87 fatal(0, "need to resample audio data but libsamplerate not available");
88 #endif
89 }
90 }
91
92 /** @brief Destroy a resampler
93 * @param rs Resampler
94 */
95 void resample_close(struct resampler *rs) {
96 #if HAVE_SAMPLERATE_H
97 if(rs->state)
98 src_delete(rs->state);
99 #endif
100 }
101
102 /** @brief Get one sample value and normalize it to [-1,1]
103 * @param rs Resampler state
104 * @param bytes Pointer to input data
105 * @param where Where to store result
106 * @return Number of bytes consumed
107 */
108 static size_t resample_get_sample(const struct resampler *rs,
109 const uint8_t *bytes,
110 float *where) {
111 switch(rs->input_bits + rs->input_signed + rs->input_endian) {
112 case 8+ENDIAN_BIG:
113 case 8+ENDIAN_LITTLE:
114 *where = (bytes[0] - 128)/ 128.0;
115 return 1;
116 case 8+SIGNED+ENDIAN_BIG:
117 case 8+SIGNED+ENDIAN_LITTLE:
118 *where = (int8_t)bytes[0] / 128.0;
119 return 1;
120 case 16+ENDIAN_BIG:
121 *where = (bytes[0] * 256 + bytes[1] - 32768)/ 32768.0;
122 return 2;
123 break;
124 case 16+ENDIAN_LITTLE:
125 *where = (bytes[1] * 256 + bytes[0] - 32768)/ 32768.0;
126 return 2;
127 break;
128 case 16+SIGNED+ENDIAN_BIG:
129 *where = (int16_t)(bytes[0] * 256 + bytes[1])/ 32768.0;
130 return 2;
131 break;
132 case 16+SIGNED+ENDIAN_LITTLE:
133 *where = (int16_t)(bytes[1] * 256 + bytes[0])/ 32768.0;
134 return 2;
135 break;
136 default:
137 assert(!"unsupported sample format");
138 }
139 }
140
141 static inline int clip(int n, int min, int max) {
142 if(n >= min) {
143 if(n <= max)
144 return n;
145 else
146 return max;
147 } else
148 return min;
149 }
150
151 /** @brief Store one sample value
152 * @param rs Resampler state
153 * @param sample Sample value
154 * @param bytes Where to store it
155 * @return Number of bytes stored
156 *
157 * The value is clipped naively if it will not fit.
158 */
159 static size_t resample_put_sample(const struct resampler *rs,
160 float sample,
161 uint8_t *bytes) {
162 unsigned value;
163 switch(rs->output_bits + rs->output_signed + rs->output_endian) {
164 case 8+ENDIAN_BIG:
165 case 8+ENDIAN_LITTLE:
166 *bytes = clip(sample * 128.0 + 128, 0, 255);
167 return 1;
168 case 8+SIGNED+ENDIAN_BIG:
169 case 8+SIGNED+ENDIAN_LITTLE:
170 *bytes = clip((int)(sample * 128.0), -128, 127);
171 return 1;
172 case 16+ENDIAN_BIG: /* unsigned */
173 value = clip(sample * 32768.0 + 32768, 0, 65535);
174 *bytes++ = value >> 8;
175 *bytes++ = value;
176 return 2;
177 case 16+ENDIAN_LITTLE:
178 value = clip(sample * 32768.0 + 32768, 0, 65535);
179 *bytes++ = value;
180 *bytes++ = value >> 8;
181 return 2;
182 case 16+SIGNED+ENDIAN_BIG:
183 value = clip(sample * 32768.0, -32768, 32767);
184 *bytes++ = value >> 8;
185 *bytes++ = value;
186 return 2;
187 case 16+SIGNED+ENDIAN_LITTLE:
188 value = clip(sample * 32768.0, -32768, 32767);
189 *bytes++ = value;
190 *bytes++ = value >> 8;
191 return 2;
192 default:
193 assert(!"unsupported sample format");
194 }
195 }
196
197 /** @brief Convert input samples to floats
198 * @param rs Resampler state
199 * @param bytes Input bytes
200 * @param nbytes Number of input bytes
201 * @param floats Where to store converted data
202 *
203 * @p floats must be big enough. As well as converting to floats this
204 * also converts to the output's channel format.
205 *
206 * Excess input channels are just discarded. If there are insufficient input
207 * channels the last one is duplicated as often as necessary to make up the
208 * numbers. This is a rather naff heuristic and may be improved in a future
209 * version, but mostly in DisOrder the output is pretty much always stereo and
210 * the input either mono or stereo, so the result isn't actually going to be
211 * too bad.
212 */
213 static void resample_prepare_input(const struct resampler *rs,
214 const uint8_t *bytes,
215 size_t nbytes,
216 float *floats) {
217 size_t nframes = nbytes / (rs->input_bytes_per_frame);
218
219 while(nframes > 0) {
220 int n;
221
222 for(n = 0; n < rs->input_channels && n < rs->output_channels; ++n) {
223 bytes += resample_get_sample(rs, bytes, floats);
224 ++floats;
225 }
226 if(n < rs->input_channels) {
227 /* More input channels; discard them */
228 bytes += (rs->input_channels - n) * rs->input_bytes_per_sample;
229 } else if(n < rs->output_channels) {
230 /* More output channels; duplicate the last input channel */
231 for(; n < rs->output_channels; ++n) {
232 *floats = floats[-1];
233 ++floats;
234 }
235 }
236 --nframes;
237 }
238 }
239
240 /** @brief Convert between sample formats
241 * @param rs Resampler state
242 * @param bytes Bytes to convert
243 * @param nbytes Number of bytes to convert
244 * @param eof Set an end of input stream
245 * @param converted Called with converted data (possibly more than once)
246 * @param cd Passed to @p cd
247 * @return Number of bytes consumed
248 */
249 size_t resample_convert(const struct resampler *rs,
250 const uint8_t *bytes,
251 size_t nbytes,
252 int eof,
253 void (*converted)(uint8_t *bytes,
254 size_t nbytes,
255 void *cd),
256 void *cd) {
257 size_t nframesin = nbytes / (rs->input_bytes_per_frame);
258 size_t nsamplesout;
259 float *input = xcalloc(nframesin * rs->output_channels, sizeof (float));
260 float *output = 0;
261
262 resample_prepare_input(rs, bytes, nbytes, input);
263 #if HAVE_SAMPLERATE_H
264 if(rs->state) {
265 /* A sample-rate conversion must be performed */
266 SRC_DATA data;
267 /* Compute how many frames are expected to come out. */
268 size_t maxframesout = nframesin * rs->output_rate / rs->input_rate + 1;
269 output = xcalloc(maxframesout * rs->output_channels, sizeof(float));
270 data.data_in = input;
271 data.data_out = output;
272 data.input_frames = nframesin;
273 data.output_frames = maxframesout;
274 data.end_of_input = eof;
275 data.src_ratio = rs->output_rate / rs->input_rate;
276 int error_ = src_process(rs->state, &data);
277 if(error_)
278 fatal(0, "calling src_process: %s", src_strerror(error_));
279 nframesin = data.input_frames_used;
280 nsamplesout = data.output_frames_gen * rs->output_channels;
281 }
282 #endif
283 if(!output) {
284 /* No sample-rate conversion required */
285 output = input;
286 nsamplesout = nframesin * rs->output_channels;
287 }
288 const float *op = output;
289 while(nsamplesout > 0) {
290 uint8_t buffer[4096];
291 size_t bufused = 0;
292
293 while(bufused < sizeof buffer && nsamplesout > 0) {
294 bufused += resample_put_sample(rs, *op++, buffer + bufused);
295 --nsamplesout;
296 }
297 converted(buffer, bufused, cd);
298 }
299 if(output != input)
300 xfree(output);
301 xfree(input);
302 /* Report how many input bytes were actually consumed */
303 return nframesin * rs->input_bytes_per_frame;
304 }
305
306 /*
307 Local Variables:
308 c-basic-offset:2
309 comment-column:40
310 fill-column:79
311 indent-tabs-mode:nil
312 End:
313 */