153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 553a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 653a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 753a5a1b3Sopenharmony_ci or (at your option) any later version. 853a5a1b3Sopenharmony_ci 953a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1053a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1153a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1253a5a1b3Sopenharmony_ci General Public License for more details. 1353a5a1b3Sopenharmony_ci 1453a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1553a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1653a5a1b3Sopenharmony_ci***/ 1753a5a1b3Sopenharmony_ci 1853a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 1953a5a1b3Sopenharmony_ci#include <config.h> 2053a5a1b3Sopenharmony_ci#endif 2153a5a1b3Sopenharmony_ci 2253a5a1b3Sopenharmony_ci#include <stdio.h> 2353a5a1b3Sopenharmony_ci#include <getopt.h> 2453a5a1b3Sopenharmony_ci#include <locale.h> 2553a5a1b3Sopenharmony_ci#include <math.h> 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <pulse/pulseaudio.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <pulse/rtclock.h> 3053a5a1b3Sopenharmony_ci#include <pulse/sample.h> 3153a5a1b3Sopenharmony_ci#include <pulse/volume.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h> 3453a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3553a5a1b3Sopenharmony_ci#include <pulsecore/resampler.h> 3653a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 3753a5a1b3Sopenharmony_ci#include <pulsecore/endianmacros.h> 3853a5a1b3Sopenharmony_ci#include <pulsecore/memblock.h> 3953a5a1b3Sopenharmony_ci#include <pulsecore/memblockq.h> 4053a5a1b3Sopenharmony_ci#include <pulsecore/sample-util.h> 4153a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 4253a5a1b3Sopenharmony_ci 4353a5a1b3Sopenharmony_ci#define MEMBLOCKQ_MAXLENGTH (16*1024*1024) 4453a5a1b3Sopenharmony_ci#define PA_SILENCE_MAX (pa_page_size()*16) 4553a5a1b3Sopenharmony_ci#define MAX_MATCHING_PERIOD 500 4653a5a1b3Sopenharmony_ci 4753a5a1b3Sopenharmony_cistatic pa_memblock *silence_memblock_new(pa_mempool *pool, uint8_t c) { 4853a5a1b3Sopenharmony_ci pa_memblock *b; 4953a5a1b3Sopenharmony_ci size_t length; 5053a5a1b3Sopenharmony_ci void *data; 5153a5a1b3Sopenharmony_ci 5253a5a1b3Sopenharmony_ci pa_assert(pool); 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_ci length = PA_MIN(pa_mempool_block_size_max(pool), PA_SILENCE_MAX); 5553a5a1b3Sopenharmony_ci 5653a5a1b3Sopenharmony_ci b = pa_memblock_new(pool, length); 5753a5a1b3Sopenharmony_ci 5853a5a1b3Sopenharmony_ci data = pa_memblock_acquire(b); 5953a5a1b3Sopenharmony_ci memset(data, c, length); 6053a5a1b3Sopenharmony_ci pa_memblock_release(b); 6153a5a1b3Sopenharmony_ci 6253a5a1b3Sopenharmony_ci pa_memblock_set_is_silence(b, true); 6353a5a1b3Sopenharmony_ci 6453a5a1b3Sopenharmony_ci return b; 6553a5a1b3Sopenharmony_ci} 6653a5a1b3Sopenharmony_ci 6753a5a1b3Sopenharmony_ci/* Calculate number of history bytes needed for the rewind */ 6853a5a1b3Sopenharmony_cistatic size_t calculate_resampler_history_bytes(pa_resampler *r, size_t in_rewind_frames) { 6953a5a1b3Sopenharmony_ci size_t history_frames, history_max, matching_period, total_frames, remainder; 7053a5a1b3Sopenharmony_ci double delay; 7153a5a1b3Sopenharmony_ci 7253a5a1b3Sopenharmony_ci if (!r) 7353a5a1b3Sopenharmony_ci return 0; 7453a5a1b3Sopenharmony_ci 7553a5a1b3Sopenharmony_ci /* Initialize some variables, cut off full seconds from the rewind */ 7653a5a1b3Sopenharmony_ci total_frames = 0; 7753a5a1b3Sopenharmony_ci in_rewind_frames = in_rewind_frames % r->i_ss.rate; 7853a5a1b3Sopenharmony_ci history_max = (uint64_t) PA_RESAMPLER_MAX_DELAY_USEC * r->i_ss.rate * 3 / PA_USEC_PER_SEC / 2; 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci /* Get the current internal delay of the resampler */ 8153a5a1b3Sopenharmony_ci delay = pa_resampler_get_delay(r, false); 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci /* Calculate the matchiung period */ 8453a5a1b3Sopenharmony_ci matching_period = r->i_ss.rate / pa_resampler_get_gcd(r); 8553a5a1b3Sopenharmony_ci pa_log_debug("Integral period length is %lu input frames", matching_period); 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_ci /* If the delay is larger than the length of the history queue, we can only 8853a5a1b3Sopenharmony_ci * replay as much as we have. */ 8953a5a1b3Sopenharmony_ci if ((size_t)delay >= history_max) { 9053a5a1b3Sopenharmony_ci history_frames = history_max; 9153a5a1b3Sopenharmony_ci return history_frames * r->i_fz; 9253a5a1b3Sopenharmony_ci } 9353a5a1b3Sopenharmony_ci 9453a5a1b3Sopenharmony_ci /* Initially set the history to 3 times the resampler delay. Use at least 2 ms. */ 9553a5a1b3Sopenharmony_ci history_frames = (size_t)(delay * 3.0); 9653a5a1b3Sopenharmony_ci history_frames = PA_MAX(history_frames, r->i_ss.rate / 500); 9753a5a1b3Sopenharmony_ci 9853a5a1b3Sopenharmony_ci /* Check how the rewind fits into multiples of the matching period. */ 9953a5a1b3Sopenharmony_ci remainder = (in_rewind_frames + history_frames) % matching_period; 10053a5a1b3Sopenharmony_ci 10153a5a1b3Sopenharmony_ci /* If possible, use between 2 and 3 times the resampler delay */ 10253a5a1b3Sopenharmony_ci if (remainder < (size_t)delay && history_frames - remainder <= history_max) 10353a5a1b3Sopenharmony_ci total_frames = in_rewind_frames + history_frames - remainder; 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci /* Else, try above 3 times the delay */ 10653a5a1b3Sopenharmony_ci else if (history_frames + matching_period - remainder <= history_max) 10753a5a1b3Sopenharmony_ci total_frames = in_rewind_frames + history_frames + matching_period - remainder; 10853a5a1b3Sopenharmony_ci 10953a5a1b3Sopenharmony_ci if (total_frames != 0) 11053a5a1b3Sopenharmony_ci /* We found a perfect match. */ 11153a5a1b3Sopenharmony_ci history_frames = total_frames - in_rewind_frames; 11253a5a1b3Sopenharmony_ci else { 11353a5a1b3Sopenharmony_ci /* Try to use 2.5 times the delay. */ 11453a5a1b3Sopenharmony_ci history_frames = PA_MIN((size_t)(delay * 2.5), history_max); 11553a5a1b3Sopenharmony_ci pa_log_debug("No usable integral matching period"); 11653a5a1b3Sopenharmony_ci } 11753a5a1b3Sopenharmony_ci 11853a5a1b3Sopenharmony_ci return history_frames * r->i_fz; 11953a5a1b3Sopenharmony_ci} 12053a5a1b3Sopenharmony_ci 12153a5a1b3Sopenharmony_cistatic float compare_blocks(const pa_sample_spec *ss, const pa_memchunk *chunk_a, const pa_memchunk *chunk_b) { 12253a5a1b3Sopenharmony_ci float *a, *b, max_diff = 0; 12353a5a1b3Sopenharmony_ci unsigned i; 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci a = pa_memblock_acquire(chunk_a->memblock); 12653a5a1b3Sopenharmony_ci b = pa_memblock_acquire(chunk_b->memblock); 12753a5a1b3Sopenharmony_ci a += chunk_a->index / pa_frame_size(ss); 12853a5a1b3Sopenharmony_ci b += chunk_b->index / pa_frame_size(ss); 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci for (i = 0; i < chunk_a->length / pa_frame_size(ss); i++) { 13153a5a1b3Sopenharmony_ci if (fabs(a[i] - b[i]) > max_diff) 13253a5a1b3Sopenharmony_ci max_diff = fabs(a[i] - b[i]); 13353a5a1b3Sopenharmony_ci } 13453a5a1b3Sopenharmony_ci 13553a5a1b3Sopenharmony_ci pa_memblock_release(chunk_a->memblock); 13653a5a1b3Sopenharmony_ci pa_memblock_release(chunk_b->memblock); 13753a5a1b3Sopenharmony_ci 13853a5a1b3Sopenharmony_ci return max_diff; 13953a5a1b3Sopenharmony_ci} 14053a5a1b3Sopenharmony_ci 14153a5a1b3Sopenharmony_cistatic pa_memblock* generate_block(pa_mempool *pool, const pa_sample_spec *ss, unsigned frequency, double amplitude, size_t nr_of_samples) { 14253a5a1b3Sopenharmony_ci pa_memblock *r; 14353a5a1b3Sopenharmony_ci float *d; 14453a5a1b3Sopenharmony_ci float val; 14553a5a1b3Sopenharmony_ci unsigned i; 14653a5a1b3Sopenharmony_ci int n; 14753a5a1b3Sopenharmony_ci float t, dt, dt_period; 14853a5a1b3Sopenharmony_ci 14953a5a1b3Sopenharmony_ci pa_assert(frequency); 15053a5a1b3Sopenharmony_ci pa_assert(nr_of_samples); 15153a5a1b3Sopenharmony_ci pa_assert(ss->channels == 1); 15253a5a1b3Sopenharmony_ci pa_assert(ss->format == PA_SAMPLE_FLOAT32NE); 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_ci pa_assert_se(r = pa_memblock_new(pool, pa_frame_size(ss) * nr_of_samples)); 15553a5a1b3Sopenharmony_ci d = pa_memblock_acquire(r); 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_ci /* Generate square wave with given length, frequency and sample rate. */ 15853a5a1b3Sopenharmony_ci val = amplitude; 15953a5a1b3Sopenharmony_ci t = 0; 16053a5a1b3Sopenharmony_ci n = 1; 16153a5a1b3Sopenharmony_ci dt = 1.0 / ss->rate; 16253a5a1b3Sopenharmony_ci dt_period = 1.0 / frequency; 16353a5a1b3Sopenharmony_ci for (i=0; i < nr_of_samples; i++) { 16453a5a1b3Sopenharmony_ci d[i] = val; 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci if ((int)(2 * t / dt_period) >= n) { 16753a5a1b3Sopenharmony_ci n++; 16853a5a1b3Sopenharmony_ci if (val >= amplitude) 16953a5a1b3Sopenharmony_ci val = - amplitude; 17053a5a1b3Sopenharmony_ci else 17153a5a1b3Sopenharmony_ci val = amplitude; 17253a5a1b3Sopenharmony_ci } 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_ci t += dt; 17553a5a1b3Sopenharmony_ci } 17653a5a1b3Sopenharmony_ci 17753a5a1b3Sopenharmony_ci pa_memblock_release(r); 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci return r; 18053a5a1b3Sopenharmony_ci} 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_cistatic void help(const char *argv0) { 18353a5a1b3Sopenharmony_ci printf("%s [options]\n\n" 18453a5a1b3Sopenharmony_ci "-h, --help Show this help\n" 18553a5a1b3Sopenharmony_ci "-v, --verbose Print debug messages\n" 18653a5a1b3Sopenharmony_ci " --from-rate=SAMPLERATE From sample rate in Hz (defaults to 44100)\n" 18753a5a1b3Sopenharmony_ci " --to-rate=SAMPLERATE To sample rate in Hz (defaults to 44100)\n" 18853a5a1b3Sopenharmony_ci " --resample-method=METHOD Resample method (defaults to auto)\n" 18953a5a1b3Sopenharmony_ci " --frequency=unsigned Frequency of square wave\n" 19053a5a1b3Sopenharmony_ci " --samples=unsigned Number of samples for square wave\n" 19153a5a1b3Sopenharmony_ci " --rewind=unsigned Number of output samples to rewind\n" 19253a5a1b3Sopenharmony_ci "\n" 19353a5a1b3Sopenharmony_ci "This test generates samples for a square wave of given frequency, number of samples\n" 19453a5a1b3Sopenharmony_ci "and input sample rate. Then this input data is resampled to the output rate, rewound\n" 19553a5a1b3Sopenharmony_ci "by rewind samples and the rewound part is processed again. Then output is compared to\n" 19653a5a1b3Sopenharmony_ci "the result of the first pass.\n" 19753a5a1b3Sopenharmony_ci "\n" 19853a5a1b3Sopenharmony_ci "See --dump-resample-methods for possible values of resample methods.\n", 19953a5a1b3Sopenharmony_ci argv0); 20053a5a1b3Sopenharmony_ci} 20153a5a1b3Sopenharmony_ci 20253a5a1b3Sopenharmony_cienum { 20353a5a1b3Sopenharmony_ci ARG_VERSION = 256, 20453a5a1b3Sopenharmony_ci ARG_FROM_SAMPLERATE, 20553a5a1b3Sopenharmony_ci ARG_TO_SAMPLERATE, 20653a5a1b3Sopenharmony_ci ARG_FREQUENCY, 20753a5a1b3Sopenharmony_ci ARG_SAMPLES, 20853a5a1b3Sopenharmony_ci ARG_REWIND, 20953a5a1b3Sopenharmony_ci ARG_RESAMPLE_METHOD, 21053a5a1b3Sopenharmony_ci ARG_DUMP_RESAMPLE_METHODS 21153a5a1b3Sopenharmony_ci}; 21253a5a1b3Sopenharmony_ci 21353a5a1b3Sopenharmony_cistatic void dump_resample_methods(void) { 21453a5a1b3Sopenharmony_ci int i; 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci for (i = 0; i < PA_RESAMPLER_MAX; i++) 21753a5a1b3Sopenharmony_ci if (pa_resample_method_supported(i)) 21853a5a1b3Sopenharmony_ci printf("%s\n", pa_resample_method_to_string(i)); 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_ci} 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_ciint main(int argc, char *argv[]) { 22353a5a1b3Sopenharmony_ci pa_mempool *pool = NULL; 22453a5a1b3Sopenharmony_ci pa_sample_spec a, b; 22553a5a1b3Sopenharmony_ci pa_resample_method_t method; 22653a5a1b3Sopenharmony_ci int ret = 1, c; 22753a5a1b3Sopenharmony_ci unsigned samples, frequency, rewind; 22853a5a1b3Sopenharmony_ci unsigned crossover_freq = 120; 22953a5a1b3Sopenharmony_ci pa_resampler *resampler; 23053a5a1b3Sopenharmony_ci pa_memchunk in_chunk, out_chunk, rewound_chunk, silence_chunk; 23153a5a1b3Sopenharmony_ci pa_usec_t ts; 23253a5a1b3Sopenharmony_ci pa_memblockq *history_queue = NULL; 23353a5a1b3Sopenharmony_ci size_t in_rewind_size, in_frame_size, history_size, out_rewind_size, old_length, in_resampler_buffer, n_out_expected; 23453a5a1b3Sopenharmony_ci float max_diff; 23553a5a1b3Sopenharmony_ci double delay_before, delay_after, delay_expected; 23653a5a1b3Sopenharmony_ci 23753a5a1b3Sopenharmony_ci static const struct option long_options[] = { 23853a5a1b3Sopenharmony_ci {"help", 0, NULL, 'h'}, 23953a5a1b3Sopenharmony_ci {"verbose", 0, NULL, 'v'}, 24053a5a1b3Sopenharmony_ci {"version", 0, NULL, ARG_VERSION}, 24153a5a1b3Sopenharmony_ci {"from-rate", 1, NULL, ARG_FROM_SAMPLERATE}, 24253a5a1b3Sopenharmony_ci {"to-rate", 1, NULL, ARG_TO_SAMPLERATE}, 24353a5a1b3Sopenharmony_ci {"frequency", 1, NULL, ARG_FREQUENCY}, 24453a5a1b3Sopenharmony_ci {"samples", 1, NULL, ARG_SAMPLES}, 24553a5a1b3Sopenharmony_ci {"rewind", 1, NULL, ARG_REWIND}, 24653a5a1b3Sopenharmony_ci {"resample-method", 1, NULL, ARG_RESAMPLE_METHOD}, 24753a5a1b3Sopenharmony_ci {"dump-resample-methods", 0, NULL, ARG_DUMP_RESAMPLE_METHODS}, 24853a5a1b3Sopenharmony_ci {NULL, 0, NULL, 0} 24953a5a1b3Sopenharmony_ci }; 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_ci setlocale(LC_ALL, ""); 25253a5a1b3Sopenharmony_ci#ifdef ENABLE_NLS 25353a5a1b3Sopenharmony_ci bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); 25453a5a1b3Sopenharmony_ci#endif 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci pa_log_set_level(PA_LOG_WARN); 25753a5a1b3Sopenharmony_ci if (!getenv("MAKE_CHECK")) 25853a5a1b3Sopenharmony_ci pa_log_set_level(PA_LOG_INFO); 25953a5a1b3Sopenharmony_ci 26053a5a1b3Sopenharmony_ci a.channels = b.channels = 1; 26153a5a1b3Sopenharmony_ci a.rate = 48000; 26253a5a1b3Sopenharmony_ci b.rate = 44100; 26353a5a1b3Sopenharmony_ci a.format = b.format = PA_SAMPLE_FLOAT32NE; 26453a5a1b3Sopenharmony_ci 26553a5a1b3Sopenharmony_ci method = PA_RESAMPLER_AUTO; 26653a5a1b3Sopenharmony_ci frequency = 1000; 26753a5a1b3Sopenharmony_ci samples = 5000; 26853a5a1b3Sopenharmony_ci rewind = 2500; 26953a5a1b3Sopenharmony_ci 27053a5a1b3Sopenharmony_ci while ((c = getopt_long(argc, argv, "hv", long_options, NULL)) != -1) { 27153a5a1b3Sopenharmony_ci 27253a5a1b3Sopenharmony_ci switch (c) { 27353a5a1b3Sopenharmony_ci case 'h' : 27453a5a1b3Sopenharmony_ci help(argv[0]); 27553a5a1b3Sopenharmony_ci ret = 0; 27653a5a1b3Sopenharmony_ci goto quit; 27753a5a1b3Sopenharmony_ci 27853a5a1b3Sopenharmony_ci case 'v': 27953a5a1b3Sopenharmony_ci pa_log_set_level(PA_LOG_DEBUG); 28053a5a1b3Sopenharmony_ci break; 28153a5a1b3Sopenharmony_ci 28253a5a1b3Sopenharmony_ci case ARG_VERSION: 28353a5a1b3Sopenharmony_ci printf("%s %s\n", argv[0], PACKAGE_VERSION); 28453a5a1b3Sopenharmony_ci ret = 0; 28553a5a1b3Sopenharmony_ci goto quit; 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci case ARG_DUMP_RESAMPLE_METHODS: 28853a5a1b3Sopenharmony_ci dump_resample_methods(); 28953a5a1b3Sopenharmony_ci ret = 0; 29053a5a1b3Sopenharmony_ci goto quit; 29153a5a1b3Sopenharmony_ci 29253a5a1b3Sopenharmony_ci case ARG_FROM_SAMPLERATE: 29353a5a1b3Sopenharmony_ci a.rate = (uint32_t) atoi(optarg); 29453a5a1b3Sopenharmony_ci break; 29553a5a1b3Sopenharmony_ci 29653a5a1b3Sopenharmony_ci case ARG_TO_SAMPLERATE: 29753a5a1b3Sopenharmony_ci b.rate = (uint32_t) atoi(optarg); 29853a5a1b3Sopenharmony_ci break; 29953a5a1b3Sopenharmony_ci 30053a5a1b3Sopenharmony_ci case ARG_FREQUENCY: 30153a5a1b3Sopenharmony_ci frequency = (unsigned) atoi(optarg); 30253a5a1b3Sopenharmony_ci break; 30353a5a1b3Sopenharmony_ci 30453a5a1b3Sopenharmony_ci case ARG_SAMPLES: 30553a5a1b3Sopenharmony_ci samples = (unsigned) atoi(optarg); 30653a5a1b3Sopenharmony_ci break; 30753a5a1b3Sopenharmony_ci 30853a5a1b3Sopenharmony_ci case ARG_REWIND: 30953a5a1b3Sopenharmony_ci rewind = (unsigned) atoi(optarg); 31053a5a1b3Sopenharmony_ci break; 31153a5a1b3Sopenharmony_ci 31253a5a1b3Sopenharmony_ci case ARG_RESAMPLE_METHOD: 31353a5a1b3Sopenharmony_ci if (*optarg == '\0' || pa_streq(optarg, "help")) { 31453a5a1b3Sopenharmony_ci dump_resample_methods(); 31553a5a1b3Sopenharmony_ci ret = 0; 31653a5a1b3Sopenharmony_ci goto quit; 31753a5a1b3Sopenharmony_ci } 31853a5a1b3Sopenharmony_ci method = pa_parse_resample_method(optarg); 31953a5a1b3Sopenharmony_ci break; 32053a5a1b3Sopenharmony_ci 32153a5a1b3Sopenharmony_ci default: 32253a5a1b3Sopenharmony_ci goto quit; 32353a5a1b3Sopenharmony_ci } 32453a5a1b3Sopenharmony_ci } 32553a5a1b3Sopenharmony_ci 32653a5a1b3Sopenharmony_ci pa_log_info("=== Square wave %u Hz, %u samples. Resampling using %s from %u Hz to %u Hz, rewinding %u output samples.", frequency, 32753a5a1b3Sopenharmony_ci samples, pa_resample_method_to_string(method), a.rate, b.rate, rewind); 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_ci ret = 0; 33053a5a1b3Sopenharmony_ci pa_assert_se(pool = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true)); 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci pa_log_debug("Compilation CFLAGS: %s", PA_CFLAGS); 33353a5a1b3Sopenharmony_ci 33453a5a1b3Sopenharmony_ci /* Setup resampler */ 33553a5a1b3Sopenharmony_ci ts = pa_rtclock_now(); 33653a5a1b3Sopenharmony_ci pa_assert_se(resampler = pa_resampler_new(pool, &a, NULL, &b, NULL, crossover_freq, method, 0)); 33753a5a1b3Sopenharmony_ci pa_log_info("Init took %llu usec", (long long unsigned)(pa_rtclock_now() - ts)); 33853a5a1b3Sopenharmony_ci 33953a5a1b3Sopenharmony_ci /* Generate input data */ 34053a5a1b3Sopenharmony_ci in_chunk.memblock = generate_block(pool, &a, frequency, 0.5, samples); 34153a5a1b3Sopenharmony_ci in_chunk.length = pa_memblock_get_length(in_chunk.memblock); 34253a5a1b3Sopenharmony_ci in_chunk.index = 0; 34353a5a1b3Sopenharmony_ci in_frame_size = pa_frame_size(&a); 34453a5a1b3Sopenharmony_ci 34553a5a1b3Sopenharmony_ci /* First, resample the full block */ 34653a5a1b3Sopenharmony_ci ts = pa_rtclock_now(); 34753a5a1b3Sopenharmony_ci pa_resampler_run(resampler, &in_chunk, &out_chunk); 34853a5a1b3Sopenharmony_ci if (!out_chunk.memblock) { 34953a5a1b3Sopenharmony_ci pa_memblock_unref(in_chunk.memblock); 35053a5a1b3Sopenharmony_ci pa_log_warn("Resampling did not return any output data"); 35153a5a1b3Sopenharmony_ci ret = 1; 35253a5a1b3Sopenharmony_ci goto quit; 35353a5a1b3Sopenharmony_ci } 35453a5a1b3Sopenharmony_ci 35553a5a1b3Sopenharmony_ci pa_log_info("resampling took %llu usec.", (long long unsigned)(pa_rtclock_now() - ts)); 35653a5a1b3Sopenharmony_ci if (rewind > out_chunk.length / pa_frame_size(&b)) { 35753a5a1b3Sopenharmony_ci pa_log_warn("Specified number of frames to rewind (%u) larger than number of output frames (%lu), aborting.", rewind, out_chunk.length / pa_frame_size(&b)); 35853a5a1b3Sopenharmony_ci ret = 1; 35953a5a1b3Sopenharmony_ci goto quit1; 36053a5a1b3Sopenharmony_ci } 36153a5a1b3Sopenharmony_ci 36253a5a1b3Sopenharmony_ci /* Get delay after first resampling pass */ 36353a5a1b3Sopenharmony_ci delay_before = pa_resampler_get_delay(resampler, true); 36453a5a1b3Sopenharmony_ci 36553a5a1b3Sopenharmony_ci /* Create and prepare history queue */ 36653a5a1b3Sopenharmony_ci silence_chunk.memblock = silence_memblock_new(pool, 0); 36753a5a1b3Sopenharmony_ci silence_chunk.length = pa_frame_align(pa_memblock_get_length(silence_chunk.memblock), &a); 36853a5a1b3Sopenharmony_ci silence_chunk.index = 0; 36953a5a1b3Sopenharmony_ci history_queue = pa_memblockq_new("Test-Queue", 0, MEMBLOCKQ_MAXLENGTH, 0, &a, 0, 1, samples * in_frame_size, &silence_chunk); 37053a5a1b3Sopenharmony_ci pa_memblock_unref(silence_chunk.memblock); 37153a5a1b3Sopenharmony_ci 37253a5a1b3Sopenharmony_ci pa_memblockq_push(history_queue, &in_chunk); 37353a5a1b3Sopenharmony_ci pa_memblockq_drop(history_queue, samples * in_frame_size); 37453a5a1b3Sopenharmony_ci 37553a5a1b3Sopenharmony_ci in_rewind_size = pa_resampler_request(resampler, rewind * pa_frame_size(&b)); 37653a5a1b3Sopenharmony_ci out_rewind_size = rewind * pa_frame_size(&b); 37753a5a1b3Sopenharmony_ci pa_log_debug("Have to rewind %lu input frames", in_rewind_size / in_frame_size); 37853a5a1b3Sopenharmony_ci ts = pa_rtclock_now(); 37953a5a1b3Sopenharmony_ci 38053a5a1b3Sopenharmony_ci /* Now rewind the resampler */ 38153a5a1b3Sopenharmony_ci pa_memblockq_rewind(history_queue, in_rewind_size); 38253a5a1b3Sopenharmony_ci history_size = calculate_resampler_history_bytes(resampler, in_rewind_size / in_frame_size); 38353a5a1b3Sopenharmony_ci pa_log_debug("History is %lu frames.", history_size / in_frame_size); 38453a5a1b3Sopenharmony_ci pa_resampler_rewind(resampler, out_rewind_size, history_queue, history_size); 38553a5a1b3Sopenharmony_ci 38653a5a1b3Sopenharmony_ci pa_log_info("Rewind took %llu usec.", (long long unsigned)(pa_rtclock_now() - ts)); 38753a5a1b3Sopenharmony_ci ts = pa_rtclock_now(); 38853a5a1b3Sopenharmony_ci 38953a5a1b3Sopenharmony_ci /* Re-run the resampler */ 39053a5a1b3Sopenharmony_ci old_length = in_chunk.length; 39153a5a1b3Sopenharmony_ci in_chunk.length = in_rewind_size; 39253a5a1b3Sopenharmony_ci in_chunk.index = old_length - in_chunk.length; 39353a5a1b3Sopenharmony_ci pa_resampler_run(resampler, &in_chunk, &rewound_chunk); 39453a5a1b3Sopenharmony_ci if (!rewound_chunk.memblock) { 39553a5a1b3Sopenharmony_ci pa_log_warn("Resampler did not return output data for rewind"); 39653a5a1b3Sopenharmony_ci ret = 1; 39753a5a1b3Sopenharmony_ci goto quit1; 39853a5a1b3Sopenharmony_ci } 39953a5a1b3Sopenharmony_ci 40053a5a1b3Sopenharmony_ci /* Get delay after rewind */ 40153a5a1b3Sopenharmony_ci delay_after = pa_resampler_get_delay(resampler, true); 40253a5a1b3Sopenharmony_ci 40353a5a1b3Sopenharmony_ci /* Calculate expected delay */ 40453a5a1b3Sopenharmony_ci n_out_expected = pa_resampler_result(resampler, in_rewind_size + history_size) / pa_frame_size(&b); 40553a5a1b3Sopenharmony_ci delay_expected = delay_before + (double)(in_rewind_size + history_size) / (double)in_frame_size - n_out_expected * (double)a.rate / (double)b.rate; 40653a5a1b3Sopenharmony_ci 40753a5a1b3Sopenharmony_ci /* Check for leftover samples in the resampler buffer */ 40853a5a1b3Sopenharmony_ci in_resampler_buffer = lround((delay_after - delay_expected) * (double)b.rate / (double)a.rate); 40953a5a1b3Sopenharmony_ci if (in_resampler_buffer != 0) { 41053a5a1b3Sopenharmony_ci pa_log_debug("%li output frames still in resampler buffer", in_resampler_buffer); 41153a5a1b3Sopenharmony_ci } 41253a5a1b3Sopenharmony_ci 41353a5a1b3Sopenharmony_ci pa_log_info("Second resampler run took %llu usec.", (long long unsigned)(pa_rtclock_now() - ts)); 41453a5a1b3Sopenharmony_ci pa_log_debug("Got %lu output frames", rewound_chunk.length / pa_frame_size(&b)); 41553a5a1b3Sopenharmony_ci old_length = out_chunk.length; 41653a5a1b3Sopenharmony_ci out_chunk.length = rewound_chunk.length; 41753a5a1b3Sopenharmony_ci out_chunk.index = old_length - out_chunk.length; 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_ci max_diff = compare_blocks(&b, &out_chunk, &rewound_chunk); 42053a5a1b3Sopenharmony_ci pa_log_info("Maximum difference is %.*g", 6, max_diff); 42153a5a1b3Sopenharmony_ci 42253a5a1b3Sopenharmony_ci pa_memblock_unref(rewound_chunk.memblock); 42353a5a1b3Sopenharmony_ci 42453a5a1b3Sopenharmony_ciquit1: 42553a5a1b3Sopenharmony_ci pa_memblock_unref(in_chunk.memblock); 42653a5a1b3Sopenharmony_ci pa_memblock_unref(out_chunk.memblock); 42753a5a1b3Sopenharmony_ci 42853a5a1b3Sopenharmony_ci pa_resampler_free(resampler); 42953a5a1b3Sopenharmony_ci if (history_queue) 43053a5a1b3Sopenharmony_ci pa_memblockq_free(history_queue); 43153a5a1b3Sopenharmony_ci 43253a5a1b3Sopenharmony_ciquit: 43353a5a1b3Sopenharmony_ci if (pool) 43453a5a1b3Sopenharmony_ci pa_mempool_unref(pool); 43553a5a1b3Sopenharmony_ci 43653a5a1b3Sopenharmony_ci return ret; 43753a5a1b3Sopenharmony_ci} 438