1 /* Spa
2 *
3 * Copyright © 2018 Wim Taymans
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <math.h>
26 #include <errno.h>
27
28 #include <spa/param/audio/format.h>
29
30 #include "resample-peaks-impl.h"
31
resample_peaks_process_c(struct resample * r,const void * SPA_RESTRICT src[],uint32_t * in_len,void * SPA_RESTRICT dst[],uint32_t * out_len)32 static void resample_peaks_process_c(struct resample *r,
33 const void * SPA_RESTRICT src[], uint32_t *in_len,
34 void * SPA_RESTRICT dst[], uint32_t *out_len)
35 {
36 struct peaks_data *pd = r->data;
37 uint32_t c, i, o, end, chunk, o_count, i_count;
38
39 if (SPA_UNLIKELY(r->channels == 0))
40 return;
41
42 for (c = 0; c < r->channels; c++) {
43 const float *s = src[c];
44 float *d = dst[c], m = pd->max_f[c];
45
46 o_count = pd->o_count;
47 i_count = pd->i_count;
48 o = i = 0;
49
50 while (i < *in_len && o < *out_len) {
51 end = ((uint64_t) (o_count + 1) * r->i_rate) / r->o_rate;
52 end = end > i_count ? end - i_count : 0;
53 chunk = SPA_MIN(end, *in_len);
54
55 for (; i < chunk; i++)
56 m = SPA_MAX(fabsf(s[i]), m);
57
58 if (i == end) {
59 d[o++] = m;
60 m = 0.0f;
61 o_count++;
62 }
63 }
64 pd->max_f[c] = m;
65 }
66
67 *out_len = o;
68 *in_len = i;
69 pd->o_count = o_count;
70 pd->i_count = i_count + i;
71
72 while (pd->i_count >= r->i_rate) {
73 pd->i_count -= r->i_rate;
74 pd->o_count -= r->o_rate;
75 }
76 }
77
78 struct resample_info {
79 uint32_t format;
80 uint32_t cpu_flags;
81 void (*process) (struct resample *r,
82 const void * SPA_RESTRICT src[], uint32_t *in_len,
83 void * SPA_RESTRICT dst[], uint32_t *out_len);
84 };
85
86 static struct resample_info resample_table[] =
87 {
88 #if defined (HAVE_SSE)
89 { SPA_AUDIO_FORMAT_F32, SPA_CPU_FLAG_SSE, resample_peaks_process_sse, },
90 #endif
91 { SPA_AUDIO_FORMAT_F32, 0, resample_peaks_process_c, },
92 };
93
94 #define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a)
find_resample_info(uint32_t format,uint32_t cpu_flags)95 static const struct resample_info *find_resample_info(uint32_t format, uint32_t cpu_flags)
96 {
97 size_t i;
98 for (i = 0; i < SPA_N_ELEMENTS(resample_table); i++) {
99 if (resample_table[i].format == format &&
100 MATCH_CPU_FLAGS(resample_table[i].cpu_flags, cpu_flags)) {
101 return &resample_table[i];
102 }
103 }
104 return NULL;
105 }
106
impl_peaks_free(struct resample * r)107 static void impl_peaks_free(struct resample *r)
108 {
109 free(r->data);
110 r->data = NULL;
111 }
112
impl_peaks_update_rate(struct resample * r,double rate)113 static void impl_peaks_update_rate(struct resample *r, double rate)
114 {
115 }
116
impl_peaks_delay(struct resample * r)117 static uint32_t impl_peaks_delay (struct resample *r)
118 {
119 return 0;
120 }
121
impl_peaks_in_len(struct resample * r,uint32_t out_len)122 static uint32_t impl_peaks_in_len(struct resample *r, uint32_t out_len)
123 {
124 return out_len;
125 }
126
impl_peaks_reset(struct resample * r)127 static void impl_peaks_reset (struct resample *r)
128 {
129 struct peaks_data *d = r->data;
130 d->i_count = d->o_count = 0;
131 }
132
resample_peaks_init(struct resample * r)133 int resample_peaks_init(struct resample *r)
134 {
135 struct peaks_data *d;
136 const struct resample_info *info;
137
138 r->free = impl_peaks_free;
139 r->update_rate = impl_peaks_update_rate;
140
141 if ((info = find_resample_info(SPA_AUDIO_FORMAT_F32, r->cpu_flags)) == NULL)
142 return -ENOTSUP;
143
144 r->process = info->process;
145 r->reset = impl_peaks_reset;
146 r->delay = impl_peaks_delay;
147 r->in_len = impl_peaks_in_len;
148
149 d = r->data = calloc(1, sizeof(struct peaks_data) * sizeof(float) * r->channels);
150 if (r->data == NULL)
151 return -errno;
152
153 spa_log_debug(r->log, "peaks %p: in:%d out:%d features:%08x:%08x", r,
154 r->i_rate, r->o_rate, r->cpu_flags, info->cpu_flags);
155
156 r->cpu_flags = info->cpu_flags;
157 d->i_count = d->o_count = 0;
158 return 0;
159 }
160