int main (int argc, char ** argv) { double freq ; memset (input, 0, sizeof (input)) ; freq = 0.01 ; gen_windowed_sines (1, &freq, 1.0, input, BUFFER_LEN) ; if (argc == 1) single_run () ; else if (argc == 3 && strcmp (argv [1], "--best-of") == 0) { int run_count = atoi (argv [2]) ; if (run_count < 1 || run_count > 20) { printf ("Please be sensible. Run count should be in range (1, 10].\n") ; exit (1) ; } ; multi_run (run_count) ; } else usage_exit (argv [0]) ; puts ( " Duration is in seconds.\n" " Throughput is in frames/sec (more is better).\n" ) ; return 0 ; } /* main */
static double find_attenuation (double freq, int converter, int verbose) { static float input [BUFFER_LEN] ; static float output [2 * BUFFER_LEN] ; SRC_DATA src_data ; double output_peak ; int error ; gen_windowed_sines (input, BUFFER_LEN, &freq, 1) ; src_data.end_of_input = 1 ; /* Only one buffer worth of input. */ src_data.data_in = input ; src_data.input_frames = BUFFER_LEN ; src_data.src_ratio = 1.999 ; src_data.data_out = output ; src_data.output_frames = ARRAY_LEN (output) ; if ((error = src_simple (&src_data, converter, 1))) { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; exit (1) ; } ; output_peak = find_peak (output, ARRAY_LEN (output)) ; if (verbose) printf ("\tFreq : %6f InPeak : %6f OutPeak : %6f Atten : %6.2f dB\n", freq, 1.0, output_peak, 20.0 * log10 (1.0 / output_peak)) ; return 20.0 * log10 (1.0 / output_peak) ; } /* find_attenuation */
static double snr_test (SINGLE_TEST *test_data, int number, int converter, int verbose, double *conversion_rate) { static float data [BUFFER_LEN + 1] ; static float output [MAX_SPEC_LEN] ; SRC_STATE *src_state ; SRC_DATA src_data ; clock_t start_clock, clock_time ; double output_peak, snr ; int k, output_len, input_len, error ; if (verbose != 0) { printf ("\tSignal-to-Noise Ratio Test %d.\n" "\t=====================================\n", number) ; printf ("\tFrequencies : [ ") ; for (k = 0 ; k < test_data->freq_count ; k++) printf ("%6.4f ", test_data->freqs [k]) ; printf ("]\n\tSRC Ratio : %8.4f\n", test_data->src_ratio) ; } else { printf ("\tSignal-to-Noise Ratio Test %d : ", number) ; fflush (stdout) ; } ; /* Set up the output array. */ if (test_data->src_ratio >= 1.0) { output_len = MAX_SPEC_LEN ; input_len = (int) ceil (MAX_SPEC_LEN / test_data->src_ratio) ; if (input_len > BUFFER_LEN) input_len = BUFFER_LEN ; } else { input_len = BUFFER_LEN ; output_len = (int) ceil (BUFFER_LEN * test_data->src_ratio) ; output_len &= ((-1) << 4) ; if (output_len > MAX_SPEC_LEN) output_len = MAX_SPEC_LEN ; input_len = (int) ceil (output_len / test_data->src_ratio) ; } ; memset (output, 0, sizeof (output)) ; /* Generate input data array. */ gen_windowed_sines (data, input_len, test_data->freqs, test_data->freq_count) ; /* Perform sample rate conversion. */ if ((src_state = src_new (converter, 1, &error)) == NULL) { printf ("\n\nLine %d : src_new() failed : %s.\n\n", __LINE__, src_strerror (error)) ; exit (1) ; } ; src_data.end_of_input = 1 ; /* Only one buffer worth of input. */ src_data.data_in = data ; src_data.input_frames = input_len ; src_data.src_ratio = test_data->src_ratio ; src_data.data_out = output ; src_data.output_frames = output_len ; start_clock = clock () ; if ((error = src_process (src_state, &src_data))) { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; exit (1) ; } ; clock_time = clock () - start_clock ; src_state = src_delete (src_state) ; if (clock_time <= 0) clock_time = 1 ; *conversion_rate = (1.0 * output_len * CLOCKS_PER_SEC) / clock_time ; if (test_data->src_ratio < 1.0) *conversion_rate /= test_data->src_ratio ; if (verbose != 0) { printf ("\tOutput Rate : %.0f samples/sec\n", *conversion_rate) ; printf ("\tOutput Len : %ld\n", src_data.output_frames_gen) ; } ; if (abs (src_data.output_frames_gen - output_len) > 4) { printf ("\n\nLine %d : output data length should be %d.\n\n", __LINE__, output_len) ; exit (1) ; } ; /* Check output peak. */ output_peak = find_peak (output, src_data.output_frames_gen) ; if (verbose != 0) printf ("\tOutput Peak : %6.4f\n", output_peak) ; if (fabs (output_peak - test_data->peak_value) > 0.01) { printf ("\n\nLine %d : output peak (%6.4f) should be %6.4f\n\n", __LINE__, output_peak, test_data->peak_value) ; save_oct_data ("snr_test.dat", data, BUFFER_LEN, output, output_len) ; exit (1) ; } ; /* Calculate signal-to-noise ratio. */ snr = calculate_snr (output, src_data.output_frames_gen) ; if (snr < 0.0) { /* An error occurred. */ save_oct_data ("snr_test.dat", data, BUFFER_LEN, output, src_data.output_frames_gen) ; exit (1) ; } ; if (verbose != 0) printf ("\tSNR Ratio : %.2f dB\n", snr) ; if (snr < test_data->snr) { printf ("\n\nLine %d : SNR (%5.2f) should be > %6.2f dB\n\n", __LINE__, snr, test_data->snr) ; exit (1) ; } ; if (verbose != 0) puts ("\t-------------------------------------\n\tPass\n") ; else puts ("Pass") ; return snr ; } /* snr_test */
static void simple_test (int converter, int channel_count, double target_snr) { SRC_DATA src_data ; double freq, snr ; int ch, error, frames ; printf ("\t%-22s (%d channel%c) ............. ", "simple_test", channel_count, channel_count > 1 ? 's' : ' ') ; fflush (stdout) ; memset (input_serial, 0, sizeof (input_serial)) ; memset (input_interleaved, 0, sizeof (input_interleaved)) ; memset (output_interleaved, 0, sizeof (output_interleaved)) ; memset (output_serial, 0, sizeof (output_serial)) ; frames = MIN (ARRAY_LEN (input_serial) / channel_count, 1 << 16) ; /* Calculate channel_count separate windowed sine waves. */ for (ch = 0 ; ch < channel_count ; ch++) { freq = (200.0 + 33.333333333 * ch) / 44100.0 ; gen_windowed_sines (1, &freq, 1.0, input_serial + ch * frames, frames) ; } ; /* Interleave the data in preparation for SRC. */ interleave_data (input_serial, input_interleaved, frames, channel_count) ; /* Choose a converstion ratio <= 1.0. */ src_data.src_ratio = 0.95 ; src_data.data_in = input_interleaved ; src_data.input_frames = frames ; src_data.data_out = output_interleaved ; src_data.output_frames = frames ; if ((error = src_simple (&src_data, converter, channel_count))) { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; exit (1) ; } ; if (fabs (src_data.output_frames_gen - src_data.src_ratio * src_data.input_frames) > 2) { printf ("\n\nLine %d : bad output data length %ld should be %d.\n", __LINE__, src_data.output_frames_gen, (int) floor (src_data.src_ratio * src_data.input_frames)) ; printf ("\tsrc_ratio : %.4f\n", src_data.src_ratio) ; printf ("\tinput_len : %ld\n", src_data.input_frames) ; printf ("\toutput_len : %ld\n\n", src_data.output_frames_gen) ; exit (1) ; } ; /* De-interleave data so SNR can be calculated for each channel. */ deinterleave_data (output_interleaved, output_serial, frames, channel_count) ; for (ch = 0 ; ch < channel_count ; ch++) { snr = calculate_snr (output_serial + ch * frames, frames, 1) ; if (snr < target_snr) { printf ("\n\nLine %d: channel %d snr %f should be %f\n", __LINE__, ch, snr, target_snr) ; save_oct_float ("output.dat", input_serial, channel_count * frames, output_serial, channel_count * frames) ; exit (1) ; } ; } ; puts ("ok") ; return ; } /* simple_test */
static void callback_test (int converter, int channel_count, double target_snr) { TEST_CB_DATA test_callback_data ; SRC_STATE *src_state = NULL ; double freq, snr, src_ratio ; int ch, error, frames, read_total, read_count ; printf ("\t%-22s (%d channel%c) ............. ", "callback_test", channel_count, channel_count > 1 ? 's' : ' ') ; fflush (stdout) ; memset (input_serial, 0, sizeof (input_serial)) ; memset (input_interleaved, 0, sizeof (input_interleaved)) ; memset (output_interleaved, 0, sizeof (output_interleaved)) ; memset (output_serial, 0, sizeof (output_serial)) ; memset (&test_callback_data, 0, sizeof (test_callback_data)) ; frames = MIN (ARRAY_LEN (input_serial) / channel_count, 1 << 16) ; /* Calculate channel_count separate windowed sine waves. */ for (ch = 0 ; ch < channel_count ; ch++) { freq = (200.0 + 33.333333333 * ch) / 44100.0 ; gen_windowed_sines (1, &freq, 1.0, input_serial + ch * frames, frames) ; } ; /* Interleave the data in preparation for SRC. */ interleave_data (input_serial, input_interleaved, frames, channel_count) ; /* Perform sample rate conversion. */ src_ratio = 0.95 ; test_callback_data.channels = channel_count ; test_callback_data.total_frames = frames ; test_callback_data.current_frame = 0 ; test_callback_data.data = input_interleaved ; if ((src_state = src_callback_new (test_callback_func, converter, channel_count, &error, &test_callback_data)) == NULL) { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; exit (1) ; } ; read_total = 0 ; while (read_total < frames) { read_count = src_callback_read (src_state, src_ratio, frames - read_total, output_interleaved + read_total * channel_count) ; if (read_count <= 0) break ; read_total += read_count ; } ; if ((error = src_error (src_state)) != 0) { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; exit (1) ; } ; src_state = src_delete (src_state) ; if (fabs (read_total - src_ratio * frames) > 2) { printf ("\n\nLine %d : bad output data length %d should be %d.\n", __LINE__, read_total, (int) floor (src_ratio * frames)) ; printf ("\tsrc_ratio : %.4f\n", src_ratio) ; printf ("\tinput_len : %d\n", frames) ; printf ("\toutput_len : %d\n\n", read_total) ; exit (1) ; } ; /* De-interleave data so SNR can be calculated for each channel. */ deinterleave_data (output_interleaved, output_serial, frames, channel_count) ; for (ch = 0 ; ch < channel_count ; ch++) { snr = calculate_snr (output_serial + ch * frames, frames, 1) ; if (snr < target_snr) { printf ("\n\nLine %d: channel %d snr %f should be %f\n", __LINE__, ch, snr, target_snr) ; save_oct_float ("output.dat", input_serial, channel_count * frames, output_serial, channel_count * frames) ; exit (1) ; } ; } ; puts ("ok") ; return ; } /* callback_test */
static void process_test (int converter, int channel_count, double target_snr) { SRC_STATE *src_state ; SRC_DATA src_data ; double freq, snr ; int ch, error, frames, current_in, current_out ; printf ("\t%-22s (%d channel%c) ............. ", "process_test", channel_count, channel_count > 1 ? 's' : ' ') ; fflush (stdout) ; memset (input_serial, 0, sizeof (input_serial)) ; memset (input_interleaved, 0, sizeof (input_interleaved)) ; memset (output_interleaved, 0, sizeof (output_interleaved)) ; memset (output_serial, 0, sizeof (output_serial)) ; frames = MIN (ARRAY_LEN (input_serial) / channel_count, 1 << 16) ; /* Calculate channel_count separate windowed sine waves. */ for (ch = 0 ; ch < channel_count ; ch++) { freq = (200.0 + 33.333333333 * ch) / 44100.0 ; gen_windowed_sines (1, &freq, 1.0, input_serial + ch * frames, frames) ; } ; /* Interleave the data in preparation for SRC. */ interleave_data (input_serial, input_interleaved, frames, channel_count) ; /* Perform sample rate conversion. */ if ((src_state = src_new (converter, channel_count, &error)) == NULL) { printf ("\n\nLine %d : src_new() failed : %s\n\n", __LINE__, src_strerror (error)) ; exit (1) ; } ; src_data.end_of_input = 0 ; /* Set this later. */ /* Choose a converstion ratio < 1.0. */ src_data.src_ratio = 0.95 ; src_data.data_in = input_interleaved ; src_data.data_out = output_interleaved ; current_in = current_out = 0 ; while (1) { src_data.input_frames = MAX (MIN (BLOCK_LEN, frames - current_in), 0) ; src_data.output_frames = MAX (MIN (BLOCK_LEN, frames - current_out), 0) ; if ((error = src_process (src_state, &src_data))) { printf ("\n\nLine %d : %s\n\n", __LINE__, src_strerror (error)) ; exit (1) ; } ; if (src_data.end_of_input && src_data.output_frames_gen == 0) break ; current_in += src_data.input_frames_used ; current_out += src_data.output_frames_gen ; src_data.data_in += src_data.input_frames_used * channel_count ; src_data.data_out += src_data.output_frames_gen * channel_count ; src_data.end_of_input = (current_in >= frames) ? 1 : 0 ; } ; src_state = src_delete (src_state) ; if (fabs (current_out - src_data.src_ratio * current_in) > 2) { printf ("\n\nLine %d : bad output data length %d should be %d.\n", __LINE__, current_out, (int) floor (src_data.src_ratio * current_in)) ; printf ("\tsrc_ratio : %.4f\n", src_data.src_ratio) ; printf ("\tinput_len : %d\n", frames) ; printf ("\toutput_len : %d\n\n", current_out) ; exit (1) ; } ; /* De-interleave data so SNR can be calculated for each channel. */ deinterleave_data (output_interleaved, output_serial, frames, channel_count) ; for (ch = 0 ; ch < channel_count ; ch++) { snr = calculate_snr (output_serial + ch * frames, frames, 1) ; if (snr < target_snr) { printf ("\n\nLine %d: channel %d snr %f should be %f\n", __LINE__, ch, snr, target_snr) ; save_oct_float ("output.dat", input_serial, channel_count * frames, output_serial, channel_count * frames) ; exit (1) ; } ; } ; puts ("ok") ; return ; } /* process_test */