xref: /freebsd/sys/dev/sound/pcm/pcm.h (revision e1bbaa71d62c8681a576f9f5bedf475c7541bd35)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2006-2009 Ariff Abdullah <ariff@FreeBSD.org>
5  * All rights reserved.
6  * Copyright (c) 2024-2025 The FreeBSD Foundation
7  *
8  * Portions of this software were developed by Christos Margiolis
9  * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #ifndef _SND_PCM_H_
34 #define _SND_PCM_H_
35 
36 #include <sys/param.h>
37 
38 #include <dev/sound/pcm/g711.h>
39 
40 #ifndef _KERNEL
41 #include <assert.h>	/* for __assert_unreachable() */
42 #endif
43 
44 /*
45  * Automatically turn on 64bit arithmetic on suitable archs
46  * (amd64 64bit, etc..) for wider 32bit samples / integer processing.
47  */
48 #if LONG_BIT >= 64
49 #undef SND_PCM_64
50 #define SND_PCM_64	1
51 #endif
52 
53 typedef int32_t intpcm_t;
54 
55 typedef int32_t intpcm8_t;
56 typedef int32_t intpcm16_t;
57 typedef int32_t intpcm24_t;
58 
59 typedef uint32_t uintpcm_t;
60 
61 typedef uint32_t uintpcm8_t;
62 typedef uint32_t uintpcm16_t;
63 typedef uint32_t uintpcm24_t;
64 
65 #ifdef SND_PCM_64
66 typedef int64_t  intpcm32_t;
67 typedef uint64_t uintpcm32_t;
68 #else
69 typedef int32_t  intpcm32_t;
70 typedef uint32_t uintpcm32_t;
71 #endif
72 
73 typedef int64_t intpcm64_t;
74 typedef uint64_t uintpcm64_t;
75 
76 /* 32bit fixed point shift */
77 #define	PCM_FXSHIFT	8
78 
79 #define PCM_S8_MAX	  0x7f
80 #define PCM_S8_MIN	 -0x80
81 #define PCM_S16_MAX	  0x7fff
82 #define PCM_S16_MIN	 -0x8000
83 #define PCM_S24_MAX	  0x7fffff
84 #define PCM_S24_MIN	 -0x800000
85 #ifdef SND_PCM_64
86 #if LONG_BIT >= 64
87 #define PCM_S32_MAX	  0x7fffffffL
88 #define PCM_S32_MIN	 -0x80000000L
89 #else
90 #define PCM_S32_MAX	  0x7fffffffLL
91 #define PCM_S32_MIN	 -0x80000000LL
92 #endif
93 #else
94 #define PCM_S32_MAX	  0x7fffffff
95 #define PCM_S32_MIN	(-0x7fffffff - 1)
96 #endif
97 
98 /* Bytes-per-sample definition */
99 #define PCM_8_BPS	1
100 #define PCM_16_BPS	2
101 #define PCM_24_BPS	3
102 #define PCM_32_BPS	4
103 
104 #define INTPCM_T(v)	((intpcm_t)(v))
105 #define INTPCM8_T(v)	((intpcm8_t)(v))
106 #define INTPCM16_T(v)	((intpcm16_t)(v))
107 #define INTPCM24_T(v)	((intpcm24_t)(v))
108 #define INTPCM32_T(v)	((intpcm32_t)(v))
109 
110 static const struct {
111 	const uint8_t ulaw_to_u8[G711_TABLE_SIZE];
112 	const uint8_t alaw_to_u8[G711_TABLE_SIZE];
113 	const uint8_t u8_to_ulaw[G711_TABLE_SIZE];
114 	const uint8_t u8_to_alaw[G711_TABLE_SIZE];
115 } xlaw_conv_tables = {
116 	ULAW_TO_U8,
117 	ALAW_TO_U8,
118 	U8_TO_ULAW,
119 	U8_TO_ALAW
120 };
121 
122 /*
123  * Functions for reading/writing PCM integer sample values from bytes array.
124  * Since every process is done using signed integer (and to make our life less
125  * miserable), unsigned sample will be converted to its signed counterpart and
126  * restored during writing back.
127  */
128 static __always_inline __unused intpcm_t
pcm_sample_read(const uint8_t * src,uint32_t fmt)129 pcm_sample_read(const uint8_t *src, uint32_t fmt)
130 {
131 	intpcm_t v, e, m;
132 	bool s;
133 
134 	fmt = AFMT_ENCODING(fmt);
135 
136 	switch (fmt) {
137 	case AFMT_AC3:
138 		v = 0;
139 		break;
140 	case AFMT_MU_LAW:
141 		v = _G711_TO_INTPCM(xlaw_conv_tables.ulaw_to_u8, *src);
142 		break;
143 	case AFMT_A_LAW:
144 		v = _G711_TO_INTPCM(xlaw_conv_tables.alaw_to_u8, *src);
145 		break;
146 	case AFMT_S8:
147 		v = INTPCM_T((int8_t)*src);
148 		break;
149 	case AFMT_U8:
150 		v = INTPCM_T((int8_t)(*src ^ 0x80));
151 		break;
152 	case AFMT_S16_LE:
153 		v = INTPCM_T(src[0] | (int8_t)src[1] << 8);
154 		break;
155 	case AFMT_S16_BE:
156 		v = INTPCM_T(src[1] | (int8_t)src[0] << 8);
157 		break;
158 	case AFMT_U16_LE:
159 		v = INTPCM_T(src[0] | (int8_t)(src[1] ^ 0x80) << 8);
160 		break;
161 	case AFMT_U16_BE:
162 		v = INTPCM_T(src[1] | (int8_t)(src[0] ^ 0x80) << 8);
163 		break;
164 	case AFMT_S24_LE:
165 		v = INTPCM_T(src[0] | src[1] << 8 | (int8_t)src[2] << 16);
166 		break;
167 	case AFMT_S24_BE:
168 		v = INTPCM_T(src[2] | src[1] << 8 | (int8_t)src[0] << 16);
169 		break;
170 	case AFMT_U24_LE:
171 		v = INTPCM_T(src[0] | src[1] << 8 |
172 		    (int8_t)(src[2] ^ 0x80) << 16);
173 		break;
174 	case AFMT_U24_BE:
175 		v = INTPCM_T(src[2] | src[1] << 8 |
176 		    (int8_t)(src[0] ^ 0x80) << 16);
177 		break;
178 	case AFMT_S32_LE:
179 		v = INTPCM_T(src[0] | src[1] << 8 | src[2] << 16 |
180 		    (int8_t)src[3] << 24);
181 		break;
182 	case AFMT_S32_BE:
183 		v = INTPCM_T(src[3] | src[2] << 8 | src[1] << 16 |
184 		    (int8_t)src[0] << 24);
185 		break;
186 	case AFMT_U32_LE:
187 		v = INTPCM_T(src[0] | src[1] << 8 | src[2] << 16 |
188 		    (int8_t)(src[3] ^ 0x80) << 24);
189 		break;
190 	case AFMT_U32_BE:
191 		v = INTPCM_T(src[3] | src[2] << 8 | src[1] << 16 |
192 		    (int8_t)(src[0] ^ 0x80) << 24);
193 		break;
194 	case AFMT_F32_LE:	/* FALLTHROUGH */
195 	case AFMT_F32_BE:
196 		if (fmt == AFMT_F32_LE) {
197 			v = INTPCM_T(src[0] | src[1] << 8 | src[2] << 16 |
198 			    (int8_t)src[3] << 24);
199 		} else {
200 			v = INTPCM_T(src[3] | src[2] << 8 | src[1] << 16 |
201 			    (int8_t)src[0] << 24);
202 		}
203 		e = (v >> 23) & 0xff;
204 		/* NaN, +/- Inf  or too small */
205 		if (e == 0xff || e < 96) {
206 			v = INTPCM_T(0);
207 			break;
208 		}
209 		s = v & 0x80000000U;
210 		if (e > 126) {
211 			v = INTPCM_T((s == 0) ? PCM_S32_MAX : PCM_S32_MIN);
212 			break;
213 		}
214 		m = 0x800000 | (v & 0x7fffff);
215 		e += 8 - 127;
216 		if (e < 0)
217 			m >>= -e;
218 		else
219 			m <<= e;
220 		v = INTPCM_T((s == 0) ? m : -m);
221 		break;
222 	default:
223 		v = 0;
224 		printf("%s(): unknown format: 0x%08x\n", __func__, fmt);
225 		__assert_unreachable();
226 	}
227 
228 	return (v);
229 }
230 
231 /*
232  * Read sample and normalize to 32-bit magnitude.
233  */
234 static __always_inline __unused intpcm_t
pcm_sample_read_norm(const uint8_t * src,uint32_t fmt)235 pcm_sample_read_norm(const uint8_t *src, uint32_t fmt)
236 {
237 	return (pcm_sample_read(src, fmt) << (32 - AFMT_BIT(fmt)));
238 }
239 
240 /*
241  * Read sample and restrict magnitude to 24 bits.
242  */
243 static __always_inline __unused intpcm_t
pcm_sample_read_calc(const uint8_t * src,uint32_t fmt)244 pcm_sample_read_calc(const uint8_t *src, uint32_t fmt)
245 {
246 	intpcm_t v;
247 
248 	v = pcm_sample_read(src, fmt);
249 
250 #ifndef SND_PCM_64
251 	/*
252 	 * Dynamic range for humans: ~140db.
253 	 *
254 	 * 16bit = 96db (close enough)
255 	 * 24bit = 144db (perfect)
256 	 * 32bit = 196db (way too much)
257 	 *
258 	 * 24bit is pretty much sufficient for our signed integer processing.
259 	 * Also, to avoid overflow, we truncate 32bit (and only 32bit) samples
260 	 * down to 24bit (see below for the reason), unless SND_PCM_64 is
261 	 * defined.
262 	 */
263 	if (fmt & AFMT_32BIT)
264 		v >>= PCM_FXSHIFT;
265 #endif
266 
267 	return (v);
268 }
269 
270 static __always_inline __unused void
pcm_sample_write(uint8_t * dst,intpcm_t v,uint32_t fmt)271 pcm_sample_write(uint8_t *dst, intpcm_t v, uint32_t fmt)
272 {
273 	intpcm_t r, e;
274 
275 	fmt = AFMT_ENCODING(fmt);
276 
277 	if (fmt & (AFMT_F32_LE | AFMT_F32_BE)) {
278 		if (v == 0)
279 			r = 0;
280 		else if (v == PCM_S32_MAX)
281 			r = 0x3f800000;
282 		else if (v == PCM_S32_MIN)
283 			r = 0x80000000U | 0x3f800000;
284 		else {
285 			r = 0;
286 			if (v < 0) {
287 				r |= 0x80000000U;
288 				v = -v;
289 			}
290 			e = 127 - 8;
291 			while ((v & 0x7f000000) != 0) {
292 				v >>= 1;
293 				e++;
294 			}
295 			while ((v & 0x7f800000) == 0) {
296 				v <<= 1;
297 				e--;
298 			}
299 			r |= (e & 0xff) << 23;
300 			r |= v & 0x7fffff;
301 		}
302 		v = r;
303 	}
304 
305 	switch (fmt) {
306 	case AFMT_AC3:
307 		*(int16_t *)dst = 0;
308 		break;
309 	case AFMT_MU_LAW:
310 		*dst = _INTPCM_TO_G711(xlaw_conv_tables.u8_to_ulaw, v);
311 		break;
312 	case AFMT_A_LAW:
313 		*dst = _INTPCM_TO_G711(xlaw_conv_tables.u8_to_alaw, v);
314 		break;
315 	case AFMT_S8:
316 		*(int8_t *)dst = v;
317 		break;
318 	case AFMT_U8:
319 		*(int8_t *)dst = v ^ 0x80;
320 		break;
321 	case AFMT_S16_LE:
322 		dst[0] = v;
323 		dst[1] = v >> 8;
324 		break;
325 	case AFMT_S16_BE:
326 		dst[1] = v;
327 		dst[0] = v >> 8;
328 		break;
329 	case AFMT_U16_LE:
330 		dst[0] = v;
331 		dst[1] = (v >> 8) ^ 0x80;
332 		break;
333 	case AFMT_U16_BE:
334 		dst[1] = v;
335 		dst[0] = (v >> 8) ^ 0x80;
336 		break;
337 	case AFMT_S24_LE:
338 		dst[0] = v;
339 		dst[1] = v >> 8;
340 		dst[2] = v >> 16;
341 		break;
342 	case AFMT_S24_BE:
343 		dst[2] = v;
344 		dst[1] = v >> 8;
345 		dst[0] = v >> 16;
346 		break;
347 	case AFMT_U24_LE:
348 		dst[0] = v;
349 		dst[1] = v >> 8;
350 		dst[2] = (v >> 16) ^ 0x80;
351 		break;
352 	case AFMT_U24_BE:
353 		dst[2] = v;
354 		dst[1] = v >> 8;
355 		dst[0] = (v >> 16) ^ 0x80;
356 		break;
357 	case AFMT_S32_LE:	/* FALLTHROUGH */
358 	case AFMT_F32_LE:
359 		dst[0] = v;
360 		dst[1] = v >> 8;
361 		dst[2] = v >> 16;
362 		dst[3] = v >> 24;
363 		break;
364 	case AFMT_S32_BE:	/* FALLTHROUGH */
365 	case AFMT_F32_BE:
366 		dst[3] = v;
367 		dst[2] = v >> 8;
368 		dst[1] = v >> 16;
369 		dst[0] = v >> 24;
370 		break;
371 	case AFMT_U32_LE:
372 		dst[0] = v;
373 		dst[1] = v >> 8;
374 		dst[2] = v >> 16;
375 		dst[3] = (v >> 24) ^ 0x80;
376 		break;
377 	case AFMT_U32_BE:
378 		dst[3] = v;
379 		dst[2] = v >> 8;
380 		dst[1] = v >> 16;
381 		dst[0] = (v >> 24) ^ 0x80;
382 		break;
383 	default:
384 		printf("%s(): unknown format: 0x%08x\n", __func__, fmt);
385 		__assert_unreachable();
386 	}
387 }
388 
389 /*
390  * Write sample and normalize to original magnitude.
391  */
392 static __always_inline __unused void
pcm_sample_write_norm(uint8_t * dst,intpcm_t v,uint32_t fmt)393 pcm_sample_write_norm(uint8_t *dst, intpcm_t v, uint32_t fmt)
394 {
395 	pcm_sample_write(dst, v >> (32 - AFMT_BIT(fmt)), fmt);
396 }
397 
398 /*
399  * To be used with pcm_sample_read_calc().
400  */
401 static __always_inline __unused void
pcm_sample_write_calc(uint8_t * dst,intpcm_t v,uint32_t fmt)402 pcm_sample_write_calc(uint8_t *dst, intpcm_t v, uint32_t fmt)
403 {
404 #ifndef SND_PCM_64
405 	/* Shift back to 32-bit magnitude. */
406 	if (fmt & AFMT_32BIT)
407 		v <<= PCM_FXSHIFT;
408 #endif
409 	pcm_sample_write(dst, v, fmt);
410 }
411 
412 static __always_inline __unused intpcm_t
pcm_clamp(intpcm32_t sample,uint32_t fmt)413 pcm_clamp(intpcm32_t sample, uint32_t fmt)
414 {
415 	fmt = AFMT_ENCODING(fmt);
416 
417 	switch (AFMT_BIT(fmt)) {
418 	case 8:
419 		return ((sample > PCM_S8_MAX) ? PCM_S8_MAX :
420 		    ((sample < PCM_S8_MIN) ? PCM_S8_MIN : sample));
421 	case 16:
422 		return ((sample > PCM_S16_MAX) ? PCM_S16_MAX :
423 		    ((sample < PCM_S16_MIN) ? PCM_S16_MIN : sample));
424 	case 24:
425 		return ((sample > PCM_S24_MAX) ? PCM_S24_MAX :
426 		    ((sample < PCM_S24_MIN) ? PCM_S24_MIN : sample));
427 	case 32:
428 		return ((sample > PCM_S32_MAX) ? PCM_S32_MAX :
429 		    ((sample < PCM_S32_MIN) ? PCM_S32_MIN : sample));
430 	default:
431 		printf("%s(): unknown format: 0x%08x\n", __func__, fmt);
432 		__assert_unreachable();
433 	}
434 }
435 
436 static __always_inline __unused intpcm_t
pcm_clamp_calc(intpcm32_t sample,uint32_t fmt)437 pcm_clamp_calc(intpcm32_t sample, uint32_t fmt)
438 {
439 #ifndef SND_PCM_64
440 	if (fmt & AFMT_32BIT) {
441 		return ((sample > PCM_S24_MAX) ? PCM_S32_MAX :
442 		    ((sample < PCM_S24_MIN) ? PCM_S32_MIN :
443 		    sample << PCM_FXSHIFT));
444 	}
445 #endif
446 
447 	return (pcm_clamp(sample, fmt));
448 }
449 
450 #endif	/* !_SND_PCM_H_ */
451