annotate src/libsamplerate-0.1.9/tests/multi_channel_test.c @ 75:8f7fd4420df7

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