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