1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <pulsecore/macro.h>
26 #include <pulsecore/g711.h>
27 #include <pulsecore/endianmacros.h>
28
29 #include "sample-util.h"
30
pa_volume_u8_c(uint8_t * samples,const int32_t * volumes,unsigned channels,unsigned length)31 static void pa_volume_u8_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
32 unsigned channel;
33
34 for (channel = 0; length; length--) {
35 int32_t t = pa_mult_s16_volume(*samples - 0x80, volumes[channel]);
36
37 t = PA_CLAMP_UNLIKELY(t, -0x80, 0x7F);
38 *samples++ = (uint8_t) (t + 0x80);
39
40 if (PA_UNLIKELY(++channel >= channels))
41 channel = 0;
42 }
43 }
44
pa_volume_alaw_c(uint8_t * samples,const int32_t * volumes,unsigned channels,unsigned length)45 static void pa_volume_alaw_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
46 unsigned channel;
47
48 for (channel = 0; length; length--) {
49 int32_t t = pa_mult_s16_volume(st_alaw2linear16(*samples), volumes[channel]);
50
51 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
52 *samples++ = (uint8_t) st_13linear2alaw((int16_t) t >> 3);
53
54 if (PA_UNLIKELY(++channel >= channels))
55 channel = 0;
56 }
57 }
58
pa_volume_ulaw_c(uint8_t * samples,const int32_t * volumes,unsigned channels,unsigned length)59 static void pa_volume_ulaw_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
60 unsigned channel;
61
62 for (channel = 0; length; length--) {
63 int32_t t = pa_mult_s16_volume(st_ulaw2linear16(*samples), volumes[channel]);
64
65 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
66 *samples++ = (uint8_t) st_14linear2ulaw((int16_t) t >> 2);
67
68 if (PA_UNLIKELY(++channel >= channels))
69 channel = 0;
70 }
71 }
72
pa_volume_s16ne_c(int16_t * samples,const int32_t * volumes,unsigned channels,unsigned length)73 static void pa_volume_s16ne_c(int16_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
74 unsigned channel;
75
76 length /= sizeof(int16_t);
77
78 for (channel = 0; length; length--) {
79 int32_t t = pa_mult_s16_volume(*samples, volumes[channel]);
80
81 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
82 *samples++ = (int16_t) t;
83
84 if (PA_UNLIKELY(++channel >= channels))
85 channel = 0;
86 }
87 }
88
pa_volume_s16re_c(int16_t * samples,const int32_t * volumes,unsigned channels,unsigned length)89 static void pa_volume_s16re_c(int16_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
90 unsigned channel;
91
92 length /= sizeof(int16_t);
93
94 for (channel = 0; length; length--) {
95 int32_t t = pa_mult_s16_volume(PA_INT16_SWAP(*samples), volumes[channel]);
96
97 t = PA_CLAMP_UNLIKELY(t, -0x8000, 0x7FFF);
98 *samples++ = PA_INT16_SWAP((int16_t) t);
99
100 if (PA_UNLIKELY(++channel >= channels))
101 channel = 0;
102 }
103 }
104
pa_volume_float32ne_c(float * samples,const float * volumes,unsigned channels,unsigned length)105 static void pa_volume_float32ne_c(float *samples, const float *volumes, unsigned channels, unsigned length) {
106 unsigned channel;
107
108 length /= sizeof(float);
109
110 for (channel = 0; length; length--) {
111 *samples++ *= volumes[channel];
112
113 if (PA_UNLIKELY(++channel >= channels))
114 channel = 0;
115 }
116 }
117
pa_volume_float32re_c(float * samples,const float * volumes,unsigned channels,unsigned length)118 static void pa_volume_float32re_c(float *samples, const float *volumes, unsigned channels, unsigned length) {
119 unsigned channel;
120
121 length /= sizeof(float);
122
123 for (channel = 0; length; length--) {
124 float t;
125
126 t = PA_READ_FLOAT32RE(samples);
127 t *= volumes[channel];
128 PA_WRITE_FLOAT32RE(samples++, t);
129
130 if (PA_UNLIKELY(++channel >= channels))
131 channel = 0;
132 }
133 }
134
pa_volume_s32ne_c(int32_t * samples,const int32_t * volumes,unsigned channels,unsigned length)135 static void pa_volume_s32ne_c(int32_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
136 unsigned channel;
137
138 length /= sizeof(int32_t);
139
140 for (channel = 0; length; length--) {
141 int64_t t;
142
143 t = (int64_t)(*samples);
144 t = (t * volumes[channel]) >> 16;
145 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
146 *samples++ = (int32_t) t;
147
148 if (PA_UNLIKELY(++channel >= channels))
149 channel = 0;
150 }
151 }
152
pa_volume_s32re_c(int32_t * samples,const int32_t * volumes,unsigned channels,unsigned length)153 static void pa_volume_s32re_c(int32_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
154 unsigned channel;
155
156 length /= sizeof(int32_t);
157
158 for (channel = 0; length; length--) {
159 int64_t t;
160
161 t = (int64_t) PA_INT32_SWAP(*samples);
162 t = (t * volumes[channel]) >> 16;
163 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
164 *samples++ = PA_INT32_SWAP((int32_t) t);
165
166 if (PA_UNLIKELY(++channel >= channels))
167 channel = 0;
168 }
169 }
170
pa_volume_s24ne_c(uint8_t * samples,const int32_t * volumes,unsigned channels,unsigned length)171 static void pa_volume_s24ne_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
172 unsigned channel;
173 uint8_t *e;
174
175 e = samples + length;
176
177 for (channel = 0; samples < e; samples += 3) {
178 int64_t t;
179
180 t = (int64_t)((int32_t) (PA_READ24NE(samples) << 8));
181 t = (t * volumes[channel]) >> 16;
182 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
183 PA_WRITE24NE(samples, ((uint32_t) (int32_t) t) >> 8);
184
185 if (PA_UNLIKELY(++channel >= channels))
186 channel = 0;
187 }
188 }
189
pa_volume_s24re_c(uint8_t * samples,const int32_t * volumes,unsigned channels,unsigned length)190 static void pa_volume_s24re_c(uint8_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
191 unsigned channel;
192 uint8_t *e;
193
194 e = samples + length;
195
196 for (channel = 0; samples < e; samples += 3) {
197 int64_t t;
198
199 t = (int64_t)((int32_t) (PA_READ24RE(samples) << 8));
200 t = (t * volumes[channel]) >> 16;
201 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
202 PA_WRITE24RE(samples, ((uint32_t) (int32_t) t) >> 8);
203
204 if (PA_UNLIKELY(++channel >= channels))
205 channel = 0;
206 }
207 }
208
pa_volume_s24_32ne_c(uint32_t * samples,const int32_t * volumes,unsigned channels,unsigned length)209 static void pa_volume_s24_32ne_c(uint32_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
210 unsigned channel;
211
212 length /= sizeof(uint32_t);
213
214 for (channel = 0; length; length--) {
215 int64_t t;
216
217 t = (int64_t) ((int32_t) (*samples << 8));
218 t = (t * volumes[channel]) >> 16;
219 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
220 *samples++ = ((uint32_t) ((int32_t) t)) >> 8;
221
222 if (PA_UNLIKELY(++channel >= channels))
223 channel = 0;
224 }
225 }
226
pa_volume_s24_32re_c(uint32_t * samples,const int32_t * volumes,unsigned channels,unsigned length)227 static void pa_volume_s24_32re_c(uint32_t *samples, const int32_t *volumes, unsigned channels, unsigned length) {
228 unsigned channel;
229
230 length /= sizeof(uint32_t);
231
232 for (channel = 0; length; length--) {
233 int64_t t;
234
235 t = (int64_t) ((int32_t) (PA_UINT32_SWAP(*samples) << 8));
236 t = (t * volumes[channel]) >> 16;
237 t = PA_CLAMP_UNLIKELY(t, -0x80000000LL, 0x7FFFFFFFLL);
238 *samples++ = PA_UINT32_SWAP(((uint32_t) ((int32_t) t)) >> 8);
239
240 if (PA_UNLIKELY(++channel >= channels))
241 channel = 0;
242 }
243 }
244
245 static pa_do_volume_func_t do_volume_table[] = {
246 [PA_SAMPLE_U8] = (pa_do_volume_func_t) pa_volume_u8_c,
247 [PA_SAMPLE_ALAW] = (pa_do_volume_func_t) pa_volume_alaw_c,
248 [PA_SAMPLE_ULAW] = (pa_do_volume_func_t) pa_volume_ulaw_c,
249 [PA_SAMPLE_S16NE] = (pa_do_volume_func_t) pa_volume_s16ne_c,
250 [PA_SAMPLE_S16RE] = (pa_do_volume_func_t) pa_volume_s16re_c,
251 [PA_SAMPLE_FLOAT32NE] = (pa_do_volume_func_t) pa_volume_float32ne_c,
252 [PA_SAMPLE_FLOAT32RE] = (pa_do_volume_func_t) pa_volume_float32re_c,
253 [PA_SAMPLE_S32NE] = (pa_do_volume_func_t) pa_volume_s32ne_c,
254 [PA_SAMPLE_S32RE] = (pa_do_volume_func_t) pa_volume_s32re_c,
255 [PA_SAMPLE_S24NE] = (pa_do_volume_func_t) pa_volume_s24ne_c,
256 [PA_SAMPLE_S24RE] = (pa_do_volume_func_t) pa_volume_s24re_c,
257 [PA_SAMPLE_S24_32NE] = (pa_do_volume_func_t) pa_volume_s24_32ne_c,
258 [PA_SAMPLE_S24_32RE] = (pa_do_volume_func_t) pa_volume_s24_32re_c
259 };
260
pa_get_volume_func(pa_sample_format_t f)261 pa_do_volume_func_t pa_get_volume_func(pa_sample_format_t f) {
262 pa_assert(pa_sample_format_valid(f));
263
264 return do_volume_table[f];
265 }
266
pa_set_volume_func(pa_sample_format_t f,pa_do_volume_func_t func)267 void pa_set_volume_func(pa_sample_format_t f, pa_do_volume_func_t func) {
268 pa_assert(pa_sample_format_valid(f));
269
270 do_volume_table[f] = func;
271 }
272