From a579fc49ba590e4bf3324a4a20ebd84e782e36da Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 27 Sep 2022 11:25:02 +0200 Subject: [PATCH] audioconvert: move peaks functions to separate file Make a peaks finder helper and use it in the peaks resampler. --- spa/plugins/audioconvert/audioconvert.c | 8 +- spa/plugins/audioconvert/meson.build | 5 +- .../{resample-peaks-c.c => peaks-ops-c.c} | 27 +++- spa/plugins/audioconvert/peaks-ops-sse.c | 122 ++++++++++++++++++ spa/plugins/audioconvert/peaks-ops.c | 91 +++++++++++++ spa/plugins/audioconvert/peaks-ops.h | 72 +++++++++++ .../audioconvert/resample-peaks-impl.h | 92 ------------- spa/plugins/audioconvert/resample-peaks-sse.c | 64 --------- spa/plugins/audioconvert/resample-peaks.c | 101 ++++++++++----- 9 files changed, 380 insertions(+), 202 deletions(-) rename spa/plugins/audioconvert/{resample-peaks-c.c => peaks-ops-c.c} (70%) create mode 100644 spa/plugins/audioconvert/peaks-ops-sse.c create mode 100644 spa/plugins/audioconvert/peaks-ops.c create mode 100644 spa/plugins/audioconvert/peaks-ops.h delete mode 100644 spa/plugins/audioconvert/resample-peaks-impl.h delete mode 100644 spa/plugins/audioconvert/resample-peaks-sse.c diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index 0b9c4ff6f..d66184930 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -216,7 +216,7 @@ struct impl { uint32_t out_offset; unsigned int started:1; unsigned int setup:1; - unsigned int peaks:1; + unsigned int resample_peaks:1; unsigned int is_passthrough:1; unsigned int drained:1; @@ -1354,7 +1354,7 @@ static int setup_resample(struct impl *this) this->resample.quality = this->props.resample_quality; this->resample.cpu_flags = this->cpu_flags; - if (this->peaks) + if (this->resample_peaks) res = resample_peaks_init(&this->resample); else res = resample_native_init(&this->resample); @@ -2689,7 +2689,7 @@ static int impl_node_process(void *object) this->drained = draining; this->out_offset = 0; } - else if (n_samples == 0 && this->peaks) { + else if (n_samples == 0 && this->resample_peaks) { for (i = 0; i < dir->n_ports; i++) { port = GET_OUT_PORT(this, i); if (port->is_monitor || port->is_control) @@ -2852,7 +2852,7 @@ impl_init(const struct spa_handle_factory *factory, if (spa_streq(k, "clock.quantum-limit")) spa_atou32(s, &this->quantum_limit, 0); else if (spa_streq(k, "resample.peaks")) - this->peaks = spa_atob(s); + this->resample_peaks = spa_atob(s); else if (spa_streq(k, "resample.prefill")) this->resample.options |= RESAMPLE_OPTION_PREFILL; else if (spa_streq(k, "factory.mode")) { diff --git a/spa/plugins/audioconvert/meson.build b/spa/plugins/audioconvert/meson.build index ab0581e76..6f4c1f872 100644 --- a/spa/plugins/audioconvert/meson.build +++ b/spa/plugins/audioconvert/meson.build @@ -12,8 +12,8 @@ audioconvert_c = static_library('audioconvert_c', 'biquad.c', 'crossover.c', 'volume-ops-c.c', + 'peaks-ops-c.c', 'resample-native-c.c', - 'resample-peaks-c.c', 'fmt-ops-c.c' ], c_args : ['-Ofast', '-ffast-math'], dependencies : [ spa_dep ], @@ -24,8 +24,8 @@ simd_dependencies += audioconvert_c if have_sse audioconvert_sse = static_library('audioconvert_sse', ['resample-native-sse.c', - 'resample-peaks-sse.c', 'volume-ops-sse.c', + 'peaks-ops-sse.c', 'channelmix-ops-sse.c' ], c_args : [sse_args, '-Ofast', '-DHAVE_SSE'], dependencies : [ spa_dep ], @@ -101,6 +101,7 @@ endif audioconvert_lib = static_library('audioconvert', ['fmt-ops.c', 'channelmix-ops.c', + 'peaks-ops.c', 'resample-native.c', 'resample-peaks.c', 'volume-ops.c' ], diff --git a/spa/plugins/audioconvert/resample-peaks-c.c b/spa/plugins/audioconvert/peaks-ops-c.c similarity index 70% rename from spa/plugins/audioconvert/resample-peaks-c.c rename to spa/plugins/audioconvert/peaks-ops-c.c index 161e06fe0..45ab1dc69 100644 --- a/spa/plugins/audioconvert/resample-peaks-c.c +++ b/spa/plugins/audioconvert/peaks-ops-c.c @@ -1,6 +1,6 @@ /* Spa * - * Copyright © 2018 Wim Taymans + * Copyright © 2022 Wim Taymans * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -24,14 +24,27 @@ #include -#include "resample-peaks-impl.h" +#include "peaks-ops.h" -static inline float find_abs_max_c(const float *s, uint32_t n_samples, float m) +void peaks_min_max_c(struct peaks *peaks, const float * SPA_RESTRICT src, + uint32_t n_samples, float *min, float *max) +{ + uint32_t n; + float t, mi = *min, ma = *max; + for (n = 0; n < n_samples; n++) { + t = src[n]; + mi = fminf(mi, t); + ma = fmaxf(ma, t); + } + *min = mi; + *max = ma; +} + +float peaks_abs_max_c(struct peaks *peaks, const float * SPA_RESTRICT src, + uint32_t n_samples, float max) { uint32_t n; for (n = 0; n < n_samples; n++) - m = fmaxf(fabsf(s[n]), m); - return m; + max = fmaxf(fabsf(src[n]), max); + return max; } - -MAKE_PEAKS(c); diff --git a/spa/plugins/audioconvert/peaks-ops-sse.c b/spa/plugins/audioconvert/peaks-ops-sse.c new file mode 100644 index 000000000..7ceb2a8c6 --- /dev/null +++ b/spa/plugins/audioconvert/peaks-ops-sse.c @@ -0,0 +1,122 @@ +/* Spa + * + * Copyright © 2022 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include + +#include + +#include "peaks-ops.h" + +static inline float hmin_ps(__m128 val) +{ + __m128 t = _mm_movehl_ps(val, val); + t = _mm_min_ps(t, val); + val = _mm_shuffle_ps(t, t, 0x55); + val = _mm_min_ss(t, val); + return _mm_cvtss_f32(val); +} + +static inline float hmax_ps(__m128 val) +{ + __m128 t = _mm_movehl_ps(val, val); + t = _mm_max_ps(t, val); + val = _mm_shuffle_ps(t, t, 0x55); + val = _mm_max_ss(t, val); + return _mm_cvtss_f32(val); +} + +void peaks_min_max_sse(struct peaks *peaks, const float * SPA_RESTRICT src, + uint32_t n_samples, float *min, float *max) +{ + uint32_t n; + __m128 in; + __m128 mi = _mm_set1_ps(*min); + __m128 ma = _mm_set1_ps(*max); + + for (n = 0; n < n_samples; n++) { + if (SPA_IS_ALIGNED(&src[n], 16)) + break; + in = _mm_set1_ps(src[n]); + mi = _mm_min_ps(mi, in); + ma = _mm_max_ps(ma, in); + } + for (; n + 15 < n_samples; n += 16) { + in = _mm_load_ps(&src[n + 0]); + mi = _mm_min_ps(mi, in); + ma = _mm_max_ps(ma, in); + in = _mm_load_ps(&src[n + 4]); + mi = _mm_min_ps(mi, in); + ma = _mm_max_ps(ma, in); + in = _mm_load_ps(&src[n + 8]); + mi = _mm_min_ps(mi, in); + ma = _mm_max_ps(ma, in); + in = _mm_load_ps(&src[n + 12]); + mi = _mm_min_ps(mi, in); + ma = _mm_max_ps(ma, in); + } + for (; n < n_samples; n++) { + in = _mm_set1_ps(src[n]); + mi = _mm_min_ps(mi, in); + ma = _mm_max_ps(ma, in); + } + *min = hmin_ps(mi); + *max = hmax_ps(ma); +} + +float peaks_abs_max_sse(struct peaks *peaks, const float * SPA_RESTRICT src, + uint32_t n_samples, float max) +{ + uint32_t n; + __m128 in; + __m128 ma = _mm_set1_ps(max); + const __m128 mask = _mm_set1_ps(-0.0f); + + for (n = 0; n < n_samples; n++) { + if (SPA_IS_ALIGNED(&src[n], 16)) + break; + in = _mm_set1_ps(src[n]); + in = _mm_andnot_ps(mask, in); + ma = _mm_max_ps(ma, in); + } + for (; n + 15 < n_samples; n += 16) { + in = _mm_load_ps(&src[n + 0]); + in = _mm_andnot_ps(mask, in); + ma = _mm_max_ps(ma, in); + in = _mm_load_ps(&src[n + 4]); + in = _mm_andnot_ps(mask, in); + ma = _mm_max_ps(ma, in); + in = _mm_load_ps(&src[n + 8]); + in = _mm_andnot_ps(mask, in); + ma = _mm_max_ps(ma, in); + in = _mm_load_ps(&src[n + 12]); + in = _mm_andnot_ps(mask, in); + ma = _mm_max_ps(ma, in); + } + for (; n < n_samples; n++) { + in = _mm_set1_ps(src[n]); + in = _mm_andnot_ps(mask, in); + ma = _mm_max_ps(ma, in); + } + return hmax_ps(ma); +} diff --git a/spa/plugins/audioconvert/peaks-ops.c b/spa/plugins/audioconvert/peaks-ops.c new file mode 100644 index 000000000..154f17de4 --- /dev/null +++ b/spa/plugins/audioconvert/peaks-ops.c @@ -0,0 +1,91 @@ +/* Spa + * + * Copyright © 2022 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "peaks-ops.h" + +typedef void (*peaks_min_max_func_t) (struct peaks *peaks, const float * SPA_RESTRICT src, + uint32_t n_samples, float *min, float *max); +typedef float (*peaks_abs_max_func_t) (struct peaks *peaks, const float * SPA_RESTRICT src, + uint32_t n_samples, float max); + +#define MAKE(min_max,abs_max,...) \ + { min_max, abs_max, #min_max , __VA_ARGS__ } + +static const struct peaks_info { + peaks_min_max_func_t min_max; + peaks_abs_max_func_t abs_max; + const char *name; + uint32_t cpu_flags; +} peaks_table[] = +{ +#if defined (HAVE_SSE) + MAKE(peaks_min_max_sse, peaks_abs_max_sse, SPA_CPU_FLAG_SSE), +#endif + MAKE(peaks_min_max_c, peaks_abs_max_c), +}; +#undef MAKE + +#define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a) + +static const struct peaks_info *find_peaks_info(uint32_t cpu_flags) +{ + size_t i; + for (i = 0; i < SPA_N_ELEMENTS(peaks_table); i++) { + if (!MATCH_CPU_FLAGS(peaks_table[i].cpu_flags, cpu_flags)) + continue; + return &peaks_table[i]; + } + return NULL; +} + +static void impl_peaks_free(struct peaks *peaks) +{ + peaks->min_max = NULL; + peaks->abs_max = NULL; +} + +int peaks_init(struct peaks *peaks) +{ + const struct peaks_info *info; + + info = find_peaks_info(peaks->cpu_flags); + if (info == NULL) + return -ENOTSUP; + + peaks->cpu_flags = info->cpu_flags; + peaks->func_name = info->name; + peaks->free = impl_peaks_free; + peaks->min_max = info->min_max; + peaks->abs_max = info->abs_max; + return 0; +} diff --git a/spa/plugins/audioconvert/peaks-ops.h b/spa/plugins/audioconvert/peaks-ops.h new file mode 100644 index 000000000..29da79410 --- /dev/null +++ b/spa/plugins/audioconvert/peaks-ops.h @@ -0,0 +1,72 @@ +/* Spa + * + * Copyright © 2022 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include + +struct peaks { + uint32_t cpu_flags; + const char *func_name; + + struct spa_log *log; + + uint32_t flags; + + void (*min_max) (struct peaks *peaks, const float * SPA_RESTRICT src, + uint32_t n_samples, float *min, float *max); + float (*abs_max) (struct peaks *peaks, const float * SPA_RESTRICT src, + uint32_t n_samples, float max); + + void (*free) (struct peaks *peaks); +}; + +int peaks_init(struct peaks *peaks); + +#define peaks_min_max(peaks,...) (peaks)->min_max(peaks, __VA_ARGS__) +#define peaks_abs_max(peaks,...) (peaks)->abs_max(peaks, __VA_ARGS__) +#define peaks_free(peaks) (peaks)->free(peaks) + +#define DEFINE_MIN_MAX_FUNCTION(arch) \ +void peaks_min_max_##arch(struct peaks *peaks, \ + const float * SPA_RESTRICT src, \ + uint32_t n_samples, float *min, float *max); + +#define DEFINE_ABS_MAX_FUNCTION(arch) \ +float peaks_abs_max_##arch(struct peaks *peaks, \ + const float * SPA_RESTRICT src, \ + uint32_t n_samples, float max); + +#define PEAKS_OPS_MAX_ALIGN 16 + +DEFINE_MIN_MAX_FUNCTION(c); +DEFINE_ABS_MAX_FUNCTION(c); + +#if defined (HAVE_SSE) +DEFINE_MIN_MAX_FUNCTION(sse); +DEFINE_ABS_MAX_FUNCTION(sse); +#endif + +#undef DEFINE_FUNCTION diff --git a/spa/plugins/audioconvert/resample-peaks-impl.h b/spa/plugins/audioconvert/resample-peaks-impl.h deleted file mode 100644 index 9d9d55cff..000000000 --- a/spa/plugins/audioconvert/resample-peaks-impl.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Spa - * - * Copyright © 2020 Wim Taymans - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include - -#include - -#include "resample.h" - -struct peaks_data { - uint32_t o_count; - uint32_t i_count; - float max_f[]; -}; - -#define DEFINE_PEAKS(arch) \ -void resample_peaks_process_##arch(struct resample *r, \ - const void * SPA_RESTRICT src[], uint32_t *in_len, \ - void * SPA_RESTRICT dst[], uint32_t *out_len) - -#define MAKE_PEAKS(arch) \ -DEFINE_PEAKS(arch) \ -{ \ - struct peaks_data *pd = r->data; \ - uint32_t c, i, o, end, chunk, i_count, o_count; \ - \ - if (SPA_UNLIKELY(r->channels == 0)) \ - return; \ - \ - for (c = 0; c < r->channels; c++) { \ - const float *s = src[c]; \ - float *d = dst[c], m = pd->max_f[c]; \ - \ - o_count = pd->o_count; \ - i_count = pd->i_count; \ - o = i = 0; \ - \ - while (i < *in_len && o < *out_len) { \ - end = ((uint64_t) (o_count + 1) \ - * r->i_rate) / r->o_rate; \ - end = end > i_count ? end - i_count : 0; \ - chunk = SPA_MIN(end, *in_len); \ - \ - m = find_abs_max_##arch(&s[i], chunk - i, m); \ - \ - i += chunk; \ - \ - if (i == end) { \ - d[o++] = m; \ - m = 0.0f; \ - o_count++; \ - } \ - } \ - pd->max_f[c] = m; \ - } \ - *out_len = o; \ - *in_len = i; \ - pd->o_count = o_count; \ - pd->i_count = i_count + i; \ - \ - while (pd->i_count >= r->i_rate) { \ - pd->i_count -= r->i_rate; \ - pd->o_count -= r->o_rate; \ - } \ -} - - -DEFINE_PEAKS(c); -#if defined (HAVE_SSE) -DEFINE_PEAKS(sse); -#endif diff --git a/spa/plugins/audioconvert/resample-peaks-sse.c b/spa/plugins/audioconvert/resample-peaks-sse.c deleted file mode 100644 index 26adb8b91..000000000 --- a/spa/plugins/audioconvert/resample-peaks-sse.c +++ /dev/null @@ -1,64 +0,0 @@ -/* Spa - * - * Copyright © 2018 Wim Taymans - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#include - -#include - -#include "resample-peaks-impl.h" - -static inline float hmax_ps(__m128 val) -{ - __m128 t = _mm_movehl_ps(val, val); - t = _mm_max_ps(t, val); - val = _mm_shuffle_ps(t, t, 0x55); - val = _mm_max_ss(t, val); - return _mm_cvtss_f32(val); -} - -static inline float find_abs_max_sse(const float *s, uint32_t n_samples, float m) -{ - __m128 in[2], max; - uint32_t n, unrolled; - const __m128 mask = _mm_set1_ps(-0.0f); - - max = _mm_set1_ps(m); - - unrolled = n_samples & ~7; - - for (n = 0; n < unrolled; n += 8) { - in[0] = _mm_loadu_ps(&s[n + 0]); - in[1] = _mm_loadu_ps(&s[n + 4]); - in[0] = _mm_andnot_ps(mask, in[0]); - in[1] = _mm_andnot_ps(mask, in[1]); - max = _mm_max_ps(max, in[0]); - max = _mm_max_ps(max, in[1]); - } - for (; n < n_samples; n++) - m = fmaxf(fabsf(s[n]), m); - - return fmaxf(hmax_ps(max), m); -} - -MAKE_PEAKS(sse); diff --git a/spa/plugins/audioconvert/resample-peaks.c b/spa/plugins/audioconvert/resample-peaks.c index 2fa52e875..c151d60f3 100644 --- a/spa/plugins/audioconvert/resample-peaks.c +++ b/spa/plugins/audioconvert/resample-peaks.c @@ -27,40 +27,70 @@ #include -#include "resample-peaks-impl.h" +#include "peaks-ops.h" +#include "resample.h" -struct resample_info { - uint32_t format; - uint32_t cpu_flags; - void (*process) (struct resample *r, - const void * SPA_RESTRICT src[], uint32_t *in_len, - void * SPA_RESTRICT dst[], uint32_t *out_len); +struct peaks_data { + uint32_t o_count; + uint32_t i_count; + struct peaks peaks; + float max_f[]; }; -static struct resample_info resample_table[] = +static void resample_peaks_process(struct resample *r, + const void * SPA_RESTRICT src[], uint32_t *in_len, + void * SPA_RESTRICT dst[], uint32_t *out_len) { -#if defined (HAVE_SSE) - { SPA_AUDIO_FORMAT_F32, SPA_CPU_FLAG_SSE, resample_peaks_process_sse, }, -#endif - { SPA_AUDIO_FORMAT_F32, 0, resample_peaks_process_c, }, -}; + struct peaks_data *pd = r->data; + uint32_t c, i, o, end, chunk, i_count, o_count; -#define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a) -static const struct resample_info *find_resample_info(uint32_t format, uint32_t cpu_flags) -{ - size_t i; - for (i = 0; i < SPA_N_ELEMENTS(resample_table); i++) { - if (resample_table[i].format == format && - MATCH_CPU_FLAGS(resample_table[i].cpu_flags, cpu_flags)) { - return &resample_table[i]; + if (SPA_UNLIKELY(r->channels == 0)) + return; + + for (c = 0; c < r->channels; c++) { + const float *s = src[c]; + float *d = dst[c], m = pd->max_f[c]; + + o_count = pd->o_count; + i_count = pd->i_count; + o = i = 0; + + while (i < *in_len && o < *out_len) { + end = ((uint64_t) (o_count + 1) + * r->i_rate) / r->o_rate; + end = end > i_count ? end - i_count : 0; + chunk = SPA_MIN(end, *in_len); + + m = peaks_abs_max(&pd->peaks, &s[i], chunk - i, m); + + i += chunk; + + if (i == end) { + d[o++] = m; + m = 0.0f; + o_count++; + } } + pd->max_f[c] = m; + } + *out_len = o; + *in_len = i; + pd->o_count = o_count; + pd->i_count = i_count + i; + + while (pd->i_count >= r->i_rate) { + pd->i_count -= r->i_rate; + pd->o_count -= r->o_rate; } - return NULL; } static void impl_peaks_free(struct resample *r) { - free(r->data); + struct peaks_data *d = r->data; + if (d != NULL) { + peaks_free(&d->peaks); + free(d); + } r->data = NULL; } @@ -87,27 +117,32 @@ static void impl_peaks_reset (struct resample *r) int resample_peaks_init(struct resample *r) { struct peaks_data *d; - const struct resample_info *info; + int res; r->free = impl_peaks_free; r->update_rate = impl_peaks_update_rate; - if ((info = find_resample_info(SPA_AUDIO_FORMAT_F32, r->cpu_flags)) == NULL) - return -ENOTSUP; + d = calloc(1, sizeof(struct peaks_data) + sizeof(float) * r->channels); + if (d == NULL) + return -errno; - r->process = info->process; + d->peaks.log = r->log; + d->peaks.cpu_flags = r->cpu_flags; + if ((res = peaks_init(&d->peaks)) < 0) { + free(d); + return res; + } + + r->data = d; + r->process = resample_peaks_process; r->reset = impl_peaks_reset; r->delay = impl_peaks_delay; r->in_len = impl_peaks_in_len; - d = r->data = calloc(1, sizeof(struct peaks_data) + sizeof(float) * r->channels); - if (r->data == NULL) - return -errno; - spa_log_debug(r->log, "peaks %p: in:%d out:%d features:%08x:%08x", r, - r->i_rate, r->o_rate, r->cpu_flags, info->cpu_flags); + r->i_rate, r->o_rate, r->cpu_flags, d->peaks.cpu_flags); - r->cpu_flags = info->cpu_flags; + r->cpu_flags = d->peaks.cpu_flags; d->i_count = d->o_count = 0; return 0; }