]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | ** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com> | |
3 | ** All rights reserved. | |
4 | ** | |
5 | ** This code is released under 2-clause BSD license. Please see the | |
6 | ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING | |
7 | */ | |
8 | ||
9 | #include "config.h" | |
10 | ||
11 | #include <stdio.h> | |
12 | #include <stdlib.h> | |
13 | #include <string.h> | |
14 | #include <math.h> | |
15 | #include <assert.h> | |
16 | ||
17 | #if (HAVE_FFTW3) | |
18 | #include <fftw3.h> | |
19 | #else | |
20 | static inline void | |
21 | fftw_cleanup (void) | |
22 | { return ; | |
23 | } | |
24 | #endif | |
25 | ||
26 | #include <samplerate.h> | |
27 | ||
28 | #include "util.h" | |
29 | #define BUFFER_LEN 50000 | |
30 | #define BLOCK_LEN (12) | |
31 | ||
32 | #define MAX_CHANNELS 10 | |
33 | ||
34 | static void simple_test (int converter, int channel_count, double target_snr) ; | |
35 | static void process_test (int converter, int channel_count, double target_snr) ; | |
36 | static void callback_test (int converter, int channel_count, double target_snr) ; | |
37 | ||
38 | int | |
39 | main (void) | |
40 | { double target ; | |
41 | int k ; | |
42 | ||
43 | puts ("\n Zero Order Hold interpolator :") ; | |
44 | target = 38.0 ; | |
45 | for (k = 1 ; k <= 3 ; k++) | |
46 | { simple_test (SRC_ZERO_ORDER_HOLD, k, target) ; | |
47 | process_test (SRC_ZERO_ORDER_HOLD, k, target) ; | |
48 | callback_test (SRC_ZERO_ORDER_HOLD, k, target) ; | |
49 | } ; | |
50 | ||
51 | puts ("\n Linear interpolator :") ; | |
52 | target = 79.0 ; | |
53 | for (k = 1 ; k <= 3 ; k++) | |
54 | { simple_test (SRC_LINEAR, k, target) ; | |
55 | process_test (SRC_LINEAR, k, target) ; | |
56 | callback_test (SRC_LINEAR, k, target) ; | |
57 | } ; | |
58 | ||
59 | puts ("\n Sinc interpolator :") ; | |
60 | target = 100.0 ; | |
61 | for (k = 1 ; k <= MAX_CHANNELS ; k++) | |
62 | { simple_test (SRC_SINC_FASTEST, k, target) ; | |
63 | process_test (SRC_SINC_FASTEST, k, target) ; | |
64 | callback_test (SRC_SINC_FASTEST, k, target) ; | |
65 | } ; | |
66 | ||
67 | fftw_cleanup () ; | |
68 | puts ("") ; | |
69 | ||
70 | return 0 ; | |
71 | } /* main */ | |
72 | ||
73 | /*============================================================================== | |
74 | */ | |
75 | ||
76 | static float input_serial [BUFFER_LEN * MAX_CHANNELS] ; | |
77 | static float input_interleaved [BUFFER_LEN * MAX_CHANNELS] ; | |
78 | static float output_interleaved [BUFFER_LEN * MAX_CHANNELS] ; | |
79 | static float output_serial [BUFFER_LEN * MAX_CHANNELS] ; | |
80 | ||
81 | static void | |
82 | simple_test (int converter, int channel_count, double target_snr) | |
83 | { SRC_DATA src_data ; | |
84 | ||
85 | double freq, snr ; | |
86 | int ch, error, frames ; | |
87 | ||
88 | printf ("\t%-22s (%2d channel%c) ............ ", "simple_test", channel_count, channel_count > 1 ? 's' : ' ') ; | |
89 | fflush (stdout) ; | |
90 | ||
91 | assert (channel_count <= MAX_CHANNELS) ; | |
92 | ||
93 | memset (input_serial, 0, sizeof (input_serial)) ; | |
94 | memset (input_interleaved, 0, sizeof (input_interleaved)) ; | |
95 | memset (output_interleaved, 0, sizeof (output_interleaved)) ; | |
96 | memset (output_serial, 0, sizeof (output_serial)) ; | |
97 | ||
98 | frames = BUFFER_LEN ; | |
99 | ||
100 | /* Calculate channel_count separate windowed sine waves. */ | |
101 | for (ch = 0 ; ch < channel_count ; ch++) | |
102 | { freq = (200.0 + 33.333333333 * ch) / 44100.0 ; | |
103 | gen_windowed_sines (1, &freq, 1.0, input_serial + ch * frames, frames) ; | |
104 | } ; | |
105 | ||
106 | /* Interleave the data in preparation for SRC. */ | |
107 | interleave_data (input_serial, input_interleaved, frames, channel_count) ; | |
108 | ||
109 | /* Choose a converstion ratio <= 1.0. */ | |
110 | src_data.src_ratio = 0.95 ; | |
111 | ||
112 | src_data.data_in = input_interleaved ; | |
113 | src_data.input_frames = frames ; | |
114 | ||
115 | src_data.data_out = output_interleaved ; | |
116 | src_data.output_frames = frames ; | |
117 | ||
118 | if ((error = src_simple (&src_data, converter, channel_count))) | |
119 | { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; | |
120 | exit (1) ; | |
121 | } ; | |
122 | ||
123 | if (fabs (src_data.output_frames_gen - src_data.src_ratio * src_data.input_frames) > 2) | |
124 | { printf ("\n\nLine %d : bad output data length %ld should be %d.\n", __LINE__, | |
125 | src_data.output_frames_gen, (int) floor (src_data.src_ratio * src_data.input_frames)) ; | |
126 | printf ("\tsrc_ratio : %.4f\n", src_data.src_ratio) ; | |
127 | printf ("\tinput_len : %ld\n", src_data.input_frames) ; | |
128 | printf ("\toutput_len : %ld\n\n", src_data.output_frames_gen) ; | |
129 | exit (1) ; | |
130 | } ; | |
131 | ||
132 | /* De-interleave data so SNR can be calculated for each channel. */ | |
133 | deinterleave_data (output_interleaved, output_serial, frames, channel_count) ; | |
134 | ||
135 | for (ch = 0 ; ch < channel_count ; ch++) | |
136 | { snr = calculate_snr (output_serial + ch * frames, frames, 1) ; | |
137 | if (snr < target_snr) | |
138 | { printf ("\n\nLine %d: channel %d snr %f should be %f\n", __LINE__, ch, snr, target_snr) ; | |
139 | save_oct_float ("output.dat", input_serial, channel_count * frames, output_serial, channel_count * frames) ; | |
140 | exit (1) ; | |
141 | } ; | |
142 | } ; | |
143 | ||
144 | puts ("ok") ; | |
145 | ||
146 | return ; | |
147 | } /* simple_test */ | |
148 | ||
149 | /*============================================================================== | |
150 | */ | |
151 | ||
152 | static void | |
153 | process_test (int converter, int channel_count, double target_snr) | |
154 | { SRC_STATE *src_state ; | |
155 | SRC_DATA src_data ; | |
156 | ||
157 | double freq, snr ; | |
158 | int ch, error, frames, current_in, current_out ; | |
159 | ||
160 | printf ("\t%-22s (%2d channel%c) ............ ", "process_test", channel_count, channel_count > 1 ? 's' : ' ') ; | |
161 | fflush (stdout) ; | |
162 | ||
163 | assert (channel_count <= MAX_CHANNELS) ; | |
164 | ||
165 | memset (input_serial, 0, sizeof (input_serial)) ; | |
166 | memset (input_interleaved, 0, sizeof (input_interleaved)) ; | |
167 | memset (output_interleaved, 0, sizeof (output_interleaved)) ; | |
168 | memset (output_serial, 0, sizeof (output_serial)) ; | |
169 | ||
170 | frames = BUFFER_LEN ; | |
171 | ||
172 | /* Calculate channel_count separate windowed sine waves. */ | |
173 | for (ch = 0 ; ch < channel_count ; ch++) | |
174 | { freq = (400.0 + 11.333333333 * ch) / 44100.0 ; | |
175 | gen_windowed_sines (1, &freq, 1.0, input_serial + ch * frames, frames) ; | |
176 | } ; | |
177 | ||
178 | /* Interleave the data in preparation for SRC. */ | |
179 | interleave_data (input_serial, input_interleaved, frames, channel_count) ; | |
180 | ||
181 | /* Perform sample rate conversion. */ | |
182 | if ((src_state = src_new (converter, channel_count, &error)) == NULL) | |
183 | { printf ("\n\nLine %d : src_new() failed : %s\n\n", __LINE__, src_strerror (error)) ; | |
184 | exit (1) ; | |
185 | } ; | |
186 | ||
187 | src_data.end_of_input = 0 ; /* Set this later. */ | |
188 | ||
189 | /* Choose a converstion ratio < 1.0. */ | |
190 | src_data.src_ratio = 0.95 ; | |
191 | ||
192 | src_data.data_in = input_interleaved ; | |
193 | src_data.data_out = output_interleaved ; | |
194 | ||
195 | current_in = current_out = 0 ; | |
196 | ||
197 | while (1) | |
198 | { src_data.input_frames = MAX (MIN (BLOCK_LEN, frames - current_in), 0) ; | |
199 | src_data.output_frames = MAX (MIN (BLOCK_LEN, frames - current_out), 0) ; | |
200 | ||
201 | if ((error = src_process (src_state, &src_data))) | |
202 | { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; | |
203 | exit (1) ; | |
204 | } ; | |
205 | ||
206 | if (src_data.end_of_input && src_data.output_frames_gen == 0) | |
207 | break ; | |
208 | ||
209 | current_in += src_data.input_frames_used ; | |
210 | current_out += src_data.output_frames_gen ; | |
211 | ||
212 | src_data.data_in += src_data.input_frames_used * channel_count ; | |
213 | src_data.data_out += src_data.output_frames_gen * channel_count ; | |
214 | ||
215 | src_data.end_of_input = (current_in >= frames) ? 1 : 0 ; | |
216 | } ; | |
217 | ||
218 | src_state = src_delete (src_state) ; | |
219 | ||
220 | if (fabs (current_out - src_data.src_ratio * current_in) > 2) | |
221 | { printf ("\n\nLine %d : bad output data length %d should be %d.\n", __LINE__, | |
222 | current_out, (int) floor (src_data.src_ratio * current_in)) ; | |
223 | printf ("\tsrc_ratio : %.4f\n", src_data.src_ratio) ; | |
224 | printf ("\tinput_len : %d\n", frames) ; | |
225 | printf ("\toutput_len : %d\n\n", current_out) ; | |
226 | exit (1) ; | |
227 | } ; | |
228 | ||
229 | /* De-interleave data so SNR can be calculated for each channel. */ | |
230 | deinterleave_data (output_interleaved, output_serial, frames, channel_count) ; | |
231 | ||
232 | for (ch = 0 ; ch < channel_count ; ch++) | |
233 | { snr = calculate_snr (output_serial + ch * frames, frames, 1) ; | |
234 | if (snr < target_snr) | |
235 | { printf ("\n\nLine %d: channel %d snr %f should be %f\n", __LINE__, ch, snr, target_snr) ; | |
236 | save_oct_float ("output.dat", input_serial, channel_count * frames, output_serial, channel_count * frames) ; | |
237 | exit (1) ; | |
238 | } ; | |
239 | } ; | |
240 | ||
241 | puts ("ok") ; | |
242 | ||
243 | return ; | |
244 | } /* process_test */ | |
245 | ||
246 | /*============================================================================== | |
247 | */ | |
248 | ||
249 | typedef struct | |
250 | { int channels ; | |
251 | long total_frames ; | |
252 | long current_frame ; | |
253 | float *data ; | |
254 | } TEST_CB_DATA ; | |
255 | ||
256 | static long | |
257 | test_callback_func (void *cb_data, float **data) | |
258 | { TEST_CB_DATA *pcb_data ; | |
259 | ||
260 | long frames ; | |
261 | ||
262 | if ((pcb_data = cb_data) == NULL) | |
263 | return 0 ; | |
264 | ||
265 | if (data == NULL) | |
266 | return 0 ; | |
267 | ||
268 | *data = pcb_data->data + (pcb_data->current_frame * pcb_data->channels) ; | |
269 | ||
270 | if (pcb_data->total_frames - pcb_data->current_frame < BLOCK_LEN) | |
271 | frames = pcb_data->total_frames - pcb_data->current_frame ; | |
272 | else | |
273 | frames = BLOCK_LEN ; | |
274 | ||
275 | pcb_data->current_frame += frames ; | |
276 | ||
277 | return frames ; | |
278 | } /* test_callback_func */ | |
279 | ||
280 | static void | |
281 | callback_test (int converter, int channel_count, double target_snr) | |
282 | { TEST_CB_DATA test_callback_data ; | |
283 | SRC_STATE *src_state = NULL ; | |
284 | ||
285 | double freq, snr, src_ratio ; | |
286 | int ch, error, frames, read_total, read_count ; | |
287 | ||
288 | printf ("\t%-22s (%2d channel%c) ............ ", "callback_test", channel_count, channel_count > 1 ? 's' : ' ') ; | |
289 | fflush (stdout) ; | |
290 | ||
291 | assert (channel_count <= MAX_CHANNELS) ; | |
292 | ||
293 | memset (input_serial, 0, sizeof (input_serial)) ; | |
294 | memset (input_interleaved, 0, sizeof (input_interleaved)) ; | |
295 | memset (output_interleaved, 0, sizeof (output_interleaved)) ; | |
296 | memset (output_serial, 0, sizeof (output_serial)) ; | |
297 | memset (&test_callback_data, 0, sizeof (test_callback_data)) ; | |
298 | ||
299 | frames = BUFFER_LEN ; | |
300 | ||
301 | /* Calculate channel_count separate windowed sine waves. */ | |
302 | for (ch = 0 ; ch < channel_count ; ch++) | |
303 | { freq = (200.0 + 33.333333333 * ch) / 44100.0 ; | |
304 | gen_windowed_sines (1, &freq, 1.0, input_serial + ch * frames, frames) ; | |
305 | } ; | |
306 | ||
307 | /* Interleave the data in preparation for SRC. */ | |
308 | interleave_data (input_serial, input_interleaved, frames, channel_count) ; | |
309 | ||
310 | /* Perform sample rate conversion. */ | |
311 | src_ratio = 0.95 ; | |
312 | test_callback_data.channels = channel_count ; | |
313 | test_callback_data.total_frames = frames ; | |
314 | test_callback_data.current_frame = 0 ; | |
315 | test_callback_data.data = input_interleaved ; | |
316 | ||
317 | if ((src_state = src_callback_new (test_callback_func, converter, channel_count, &error, &test_callback_data)) == NULL) | |
318 | { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; | |
319 | exit (1) ; | |
320 | } ; | |
321 | ||
322 | read_total = 0 ; | |
323 | while (read_total < frames) | |
324 | { read_count = src_callback_read (src_state, src_ratio, frames - read_total, output_interleaved + read_total * channel_count) ; | |
325 | ||
326 | if (read_count <= 0) | |
327 | break ; | |
328 | ||
329 | read_total += read_count ; | |
330 | } ; | |
331 | ||
332 | if ((error = src_error (src_state)) != 0) | |
333 | { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; | |
334 | exit (1) ; | |
335 | } ; | |
336 | ||
337 | src_state = src_delete (src_state) ; | |
338 | ||
339 | if (fabs (read_total - src_ratio * frames) > 2) | |
340 | { printf ("\n\nLine %d : bad output data length %d should be %d.\n", __LINE__, | |
341 | read_total, (int) floor (src_ratio * frames)) ; | |
342 | printf ("\tsrc_ratio : %.4f\n", src_ratio) ; | |
343 | printf ("\tinput_len : %d\n", frames) ; | |
344 | printf ("\toutput_len : %d\n\n", read_total) ; | |
345 | exit (1) ; | |
346 | } ; | |
347 | ||
348 | /* De-interleave data so SNR can be calculated for each channel. */ | |
349 | deinterleave_data (output_interleaved, output_serial, frames, channel_count) ; | |
350 | ||
351 | for (ch = 0 ; ch < channel_count ; ch++) | |
352 | { snr = calculate_snr (output_serial + ch * frames, frames, 1) ; | |
353 | if (snr < target_snr) | |
354 | { printf ("\n\nLine %d: channel %d snr %f should be %f\n", __LINE__, ch, snr, target_snr) ; | |
355 | save_oct_float ("output.dat", input_serial, channel_count * frames, output_serial, channel_count * frames) ; | |
356 | exit (1) ; | |
357 | } ; | |
358 | } ; | |
359 | ||
360 | puts ("ok") ; | |
361 | ||
362 | return ; | |
363 | } /* callback_test */ | |
364 |