153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 2553a5a1b3Sopenharmony_ci#include <math.h> 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <pulsecore/resampler.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_cistruct peaks_data { /* data specific to the peak finder pseudo resampler */ 3053a5a1b3Sopenharmony_ci unsigned o_counter; 3153a5a1b3Sopenharmony_ci unsigned i_counter; 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci float max_f[PA_CHANNELS_MAX]; 3453a5a1b3Sopenharmony_ci int16_t max_i[PA_CHANNELS_MAX]; 3553a5a1b3Sopenharmony_ci}; 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_cistatic unsigned peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { 3853a5a1b3Sopenharmony_ci unsigned c, o_index = 0; 3953a5a1b3Sopenharmony_ci unsigned i, i_end = 0; 4053a5a1b3Sopenharmony_ci void *src, *dst; 4153a5a1b3Sopenharmony_ci struct peaks_data *peaks_data; 4253a5a1b3Sopenharmony_ci 4353a5a1b3Sopenharmony_ci pa_assert(r); 4453a5a1b3Sopenharmony_ci pa_assert(input); 4553a5a1b3Sopenharmony_ci pa_assert(output); 4653a5a1b3Sopenharmony_ci pa_assert(out_n_frames); 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_ci peaks_data = r->impl.data; 4953a5a1b3Sopenharmony_ci src = pa_memblock_acquire_chunk(input); 5053a5a1b3Sopenharmony_ci dst = pa_memblock_acquire_chunk(output); 5153a5a1b3Sopenharmony_ci 5253a5a1b3Sopenharmony_ci i = ((uint64_t) peaks_data->o_counter * r->i_ss.rate) / r->o_ss.rate; 5353a5a1b3Sopenharmony_ci i = i > peaks_data->i_counter ? i - peaks_data->i_counter : 0; 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci while (i_end < in_n_frames) { 5653a5a1b3Sopenharmony_ci i_end = ((uint64_t) (peaks_data->o_counter + 1) * r->i_ss.rate) / r->o_ss.rate; 5753a5a1b3Sopenharmony_ci i_end = i_end > peaks_data->i_counter ? i_end - peaks_data->i_counter : 0; 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_ci pa_assert_fp(o_index * r->w_fz < pa_memblock_get_length(output->memblock)); 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_ci /* 1ch float is treated separately, because that is the common case */ 6253a5a1b3Sopenharmony_ci if (r->work_channels == 1 && r->work_format == PA_SAMPLE_FLOAT32NE) { 6353a5a1b3Sopenharmony_ci float *s = (float*) src + i; 6453a5a1b3Sopenharmony_ci float *d = (float*) dst + o_index; 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_ci for (; i < i_end && i < in_n_frames; i++) { 6753a5a1b3Sopenharmony_ci float n = fabsf(*s++); 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci if (n > peaks_data->max_f[0]) 7053a5a1b3Sopenharmony_ci peaks_data->max_f[0] = n; 7153a5a1b3Sopenharmony_ci } 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_ci if (i == i_end) { 7453a5a1b3Sopenharmony_ci *d = peaks_data->max_f[0]; 7553a5a1b3Sopenharmony_ci peaks_data->max_f[0] = 0; 7653a5a1b3Sopenharmony_ci o_index++, peaks_data->o_counter++; 7753a5a1b3Sopenharmony_ci } 7853a5a1b3Sopenharmony_ci } else if (r->work_format == PA_SAMPLE_S16NE) { 7953a5a1b3Sopenharmony_ci int16_t *s = (int16_t*) src + r->work_channels * i; 8053a5a1b3Sopenharmony_ci int16_t *d = (int16_t*) dst + r->work_channels * o_index; 8153a5a1b3Sopenharmony_ci 8253a5a1b3Sopenharmony_ci for (; i < i_end && i < in_n_frames; i++) 8353a5a1b3Sopenharmony_ci for (c = 0; c < r->work_channels; c++) { 8453a5a1b3Sopenharmony_ci int16_t n = abs(*s++); 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_ci if (n > peaks_data->max_i[c]) 8753a5a1b3Sopenharmony_ci peaks_data->max_i[c] = n; 8853a5a1b3Sopenharmony_ci } 8953a5a1b3Sopenharmony_ci 9053a5a1b3Sopenharmony_ci if (i == i_end) { 9153a5a1b3Sopenharmony_ci for (c = 0; c < r->work_channels; c++, d++) { 9253a5a1b3Sopenharmony_ci *d = peaks_data->max_i[c]; 9353a5a1b3Sopenharmony_ci peaks_data->max_i[c] = 0; 9453a5a1b3Sopenharmony_ci } 9553a5a1b3Sopenharmony_ci o_index++, peaks_data->o_counter++; 9653a5a1b3Sopenharmony_ci } 9753a5a1b3Sopenharmony_ci } else { 9853a5a1b3Sopenharmony_ci float *s = (float*) src + r->work_channels * i; 9953a5a1b3Sopenharmony_ci float *d = (float*) dst + r->work_channels * o_index; 10053a5a1b3Sopenharmony_ci 10153a5a1b3Sopenharmony_ci for (; i < i_end && i < in_n_frames; i++) 10253a5a1b3Sopenharmony_ci for (c = 0; c < r->work_channels; c++) { 10353a5a1b3Sopenharmony_ci float n = fabsf(*s++); 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci if (n > peaks_data->max_f[c]) 10653a5a1b3Sopenharmony_ci peaks_data->max_f[c] = n; 10753a5a1b3Sopenharmony_ci } 10853a5a1b3Sopenharmony_ci 10953a5a1b3Sopenharmony_ci if (i == i_end) { 11053a5a1b3Sopenharmony_ci for (c = 0; c < r->work_channels; c++, d++) { 11153a5a1b3Sopenharmony_ci *d = peaks_data->max_f[c]; 11253a5a1b3Sopenharmony_ci peaks_data->max_f[c] = 0; 11353a5a1b3Sopenharmony_ci } 11453a5a1b3Sopenharmony_ci o_index++, peaks_data->o_counter++; 11553a5a1b3Sopenharmony_ci } 11653a5a1b3Sopenharmony_ci } 11753a5a1b3Sopenharmony_ci } 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_ci pa_memblock_release(input->memblock); 12053a5a1b3Sopenharmony_ci pa_memblock_release(output->memblock); 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_ci *out_n_frames = o_index; 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci peaks_data->i_counter += in_n_frames; 12553a5a1b3Sopenharmony_ci 12653a5a1b3Sopenharmony_ci /* Normalize counters */ 12753a5a1b3Sopenharmony_ci while (peaks_data->i_counter >= r->i_ss.rate) { 12853a5a1b3Sopenharmony_ci pa_assert(peaks_data->o_counter >= r->o_ss.rate); 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci peaks_data->i_counter -= r->i_ss.rate; 13153a5a1b3Sopenharmony_ci peaks_data->o_counter -= r->o_ss.rate; 13253a5a1b3Sopenharmony_ci } 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci return 0; 13553a5a1b3Sopenharmony_ci} 13653a5a1b3Sopenharmony_ci 13753a5a1b3Sopenharmony_cistatic void peaks_update_rates_or_reset(pa_resampler *r) { 13853a5a1b3Sopenharmony_ci struct peaks_data *peaks_data; 13953a5a1b3Sopenharmony_ci pa_assert(r); 14053a5a1b3Sopenharmony_ci 14153a5a1b3Sopenharmony_ci peaks_data = r->impl.data; 14253a5a1b3Sopenharmony_ci 14353a5a1b3Sopenharmony_ci peaks_data->i_counter = 0; 14453a5a1b3Sopenharmony_ci peaks_data->o_counter = 0; 14553a5a1b3Sopenharmony_ci} 14653a5a1b3Sopenharmony_ci 14753a5a1b3Sopenharmony_ciint pa_resampler_peaks_init(pa_resampler*r) { 14853a5a1b3Sopenharmony_ci struct peaks_data *peaks_data; 14953a5a1b3Sopenharmony_ci pa_assert(r); 15053a5a1b3Sopenharmony_ci pa_assert(r->i_ss.rate >= r->o_ss.rate); 15153a5a1b3Sopenharmony_ci pa_assert(r->work_format == PA_SAMPLE_S16NE || r->work_format == PA_SAMPLE_FLOAT32NE); 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci peaks_data = pa_xnew0(struct peaks_data, 1); 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci r->impl.resample = peaks_resample; 15653a5a1b3Sopenharmony_ci r->impl.update_rates = peaks_update_rates_or_reset; 15753a5a1b3Sopenharmony_ci r->impl.reset = peaks_update_rates_or_reset; 15853a5a1b3Sopenharmony_ci r->impl.data = peaks_data; 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci return 0; 16153a5a1b3Sopenharmony_ci} 162