Bundle libsamplerate
[audio-libsamplerate.git] / libsamplerate / tests / multi_channel_test.c
CommitLineData
8529da43
MG
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
20static inline void
21fftw_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
34static void simple_test (int converter, int channel_count, double target_snr) ;
35static void process_test (int converter, int channel_count, double target_snr) ;
36static void callback_test (int converter, int channel_count, double target_snr) ;
37
38int
39main (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
76static float input_serial [BUFFER_LEN * MAX_CHANNELS] ;
77static float input_interleaved [BUFFER_LEN * MAX_CHANNELS] ;
78static float output_interleaved [BUFFER_LEN * MAX_CHANNELS] ;
79static float output_serial [BUFFER_LEN * MAX_CHANNELS] ;
80
81static void
82simple_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
152static void
153process_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
249typedef struct
250{ int channels ;
251 long total_frames ;
252 long current_frame ;
253 float *data ;
254} TEST_CB_DATA ;
255
256static long
257test_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
280static void
281callback_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
This page took 0.029069 seconds and 4 git commands to generate.