• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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