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